45#define DEBUG_TYPE "gi-combiner"
54 cl::desc(
"Force all indexed operations to be "
55 "legal for the GlobalISel combiner"));
64 RBI(
Builder.getMF().getSubtarget().getRegBankInfo()),
65 TRI(
Builder.getMF().getSubtarget().getRegisterInfo()) {
70 return *
Builder.getMF().getSubtarget().getTargetLowering();
88 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
107 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
108 return ByteWidth -
I - 1;
128static std::optional<bool>
132 unsigned Width = MemOffset2Idx.
size();
135 bool BigEndian =
true, LittleEndian =
true;
136 for (
unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
137 auto MemOffsetAndIdx = MemOffset2Idx.
find(MemOffset);
138 if (MemOffsetAndIdx == MemOffset2Idx.
end())
140 const int64_t Idx = MemOffsetAndIdx->second - LowestIdx;
141 assert(Idx >= 0 &&
"Expected non-negative byte offset?");
144 if (!BigEndian && !LittleEndian)
148 assert((BigEndian != LittleEndian) &&
149 "Pattern cannot be both big and little endian!");
156 assert(
LI &&
"Must have LegalizerInfo to query isLegal!");
177 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
178 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
185 if (
MRI.constrainRegAttrs(ToReg, FromReg))
186 MRI.replaceRegWith(FromReg, ToReg);
188 Builder.buildCopy(FromReg, ToReg);
190 Observer.finishedChangingAllUsesOfReg();
205 unsigned ToOpcode)
const {
220 MRI.setRegBank(Reg, *RegBank);
231 if (
MI.getOpcode() != TargetOpcode::COPY)
241 MI.eraseFromParent();
250 if (!
MRI.hasOneNonDBGUse(OrigOp))
269 std::optional<MachineOperand> MaybePoisonOperand;
271 if (!Operand.isReg())
277 if (!MaybePoisonOperand)
278 MaybePoisonOperand = Operand;
287 if (!MaybePoisonOperand) {
292 B.buildCopy(
DstOp, OrigOp);
297 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
298 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
305 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
316 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
317 "Invalid instruction");
327 assert(Def &&
"Operand not defined");
328 if (!
MRI.hasOneNonDBGUse(Reg))
330 switch (Def->getOpcode()) {
331 case TargetOpcode::G_BUILD_VECTOR:
336 Ops.push_back(BuildVecMO.getReg());
338 case TargetOpcode::G_IMPLICIT_DEF: {
339 LLT OpType =
MRI.getType(Reg);
343 Undef =
Builder.buildUndef(OpType.getScalarType());
345 assert(
MRI.getType(Undef->getOperand(0).getReg()) ==
346 OpType.getScalarType() &&
347 "All undefs should have the same type");
350 for (
unsigned EltIdx = 0, EltEnd = OpType.getNumElements();
351 EltIdx != EltEnd; ++EltIdx)
352 Ops.push_back(Undef->getOperand(0).getReg());
361 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
363 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.getType(
Ops[0])}})) {
378 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
391 MI.eraseFromParent();
395 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
396 "Invalid instruction");
399 Register SrcVec1 = Shuffle.getSrc1Reg();
400 Register SrcVec2 = Shuffle.getSrc2Reg();
402 LLT SrcVec1Type =
MRI.getType(SrcVec1);
403 LLT SrcVec2Type =
MRI.getType(SrcVec2);
410 Register SrcVec1 = Shuffle.getSrc1Reg();
411 Register SrcVec2 = Shuffle.getSrc2Reg();
412 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
413 int Width =
MRI.getType(SrcVec1).getNumElements();
415 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
416 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
420 for (
int Val : Shuffle.getMask()) {
423 else if (Val < Width)
424 Extracts.
push_back(Unmerge1.getReg(Val));
426 Extracts.
push_back(Unmerge2.getReg(Val - Width));
428 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
429 if (Extracts.
size() == 1)
430 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
432 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
433 MI.eraseFromParent();
443 if (!ConcatMI1 || !ConcatMI2)
447 if (
MRI.getType(ConcatMI1->getSourceReg(0)) !=
448 MRI.getType(ConcatMI2->getSourceReg(0)))
451 LLT ConcatSrcTy =
MRI.getType(ConcatMI1->getReg(1));
452 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
454 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
458 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
459 if (i + j >= Mask.size())
461 if (Mask[i + j] != -1)
465 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
468 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
469 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
470 if (i + j >= Mask.size())
472 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
478 Ops.push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
480 Ops.push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
481 ConcatMI1->getNumSources()));
489 {TargetOpcode::G_CONCAT_VECTORS,
490 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
501 SrcTy =
MRI.getType(Reg);
503 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
510 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
516 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
519 MI.eraseFromParent();
533 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
534 "Invalid instruction kind");
535 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
537 LLT SrcType =
MRI.getType(Src1);
541 unsigned DstNumElts = DstType.isVector() ? DstType.getNumElements() : 1;
542 unsigned SrcNumElts = SrcType.isVector() ? SrcType.getNumElements() : 1;
559 if (DstNumElts < 2 * SrcNumElts && DstNumElts != 1)
564 if (DstNumElts % SrcNumElts != 0)
570 unsigned NumConcat = DstNumElts / SrcNumElts;
573 for (
unsigned i = 0; i != DstNumElts; ++i) {
580 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
581 (ConcatSrcs[i / SrcNumElts] >= 0 &&
582 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
585 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
592 for (
auto Src : ConcatSrcs) {
596 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
598 Ops.push_back(UndefReg);
611 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
619 MI.eraseFromParent();
623 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
624 "Invalid instruction kind");
627 return Mask.size() == 1;
634 int I =
MI.getOperand(3).getShuffleMask()[0];
636 LLT Src1Ty =
MRI.getType(Src1);
637 int Src1NumElts = Src1Ty.isVector() ? Src1Ty.getNumElements() : 1;
639 if (
I >= Src1NumElts) {
640 SrcReg =
MI.getOperand(2).getReg();
647 else if (!
MRI.getType(SrcReg).isVector())
648 Builder.buildCopy(DstReg, SrcReg);
650 Builder.buildExtractVectorElementConstant(DstReg, SrcReg,
I);
652 MI.eraseFromParent();
661 const LLT TyForCandidate,
662 unsigned OpcodeForCandidate,
667 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
678 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
681 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
682 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
683 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
691 OpcodeForCandidate == TargetOpcode::G_ZEXT)
693 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
694 OpcodeForCandidate == TargetOpcode::G_SEXT)
695 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
704 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
715static void InsertInsnsWithoutSideEffectsBeforeUse(
727 InsertBB = PredBB->
getMBB();
732 if (InsertBB ==
DefMI.getParent()) {
734 Inserter(InsertBB, std::next(InsertPt), UseMO);
753 unsigned CandidateLoadOpc;
755 case TargetOpcode::G_ANYEXT:
756 CandidateLoadOpc = TargetOpcode::G_LOAD;
758 case TargetOpcode::G_SEXT:
759 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
761 case TargetOpcode::G_ZEXT:
762 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
767 return CandidateLoadOpc;
784 LLT LoadValueTy =
MRI.getType(LoadReg);
806 unsigned PreferredOpcode =
808 ? TargetOpcode::G_ANYEXT
810 Preferred = {
LLT(), PreferredOpcode,
nullptr};
811 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
812 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
813 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
814 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
815 const auto &MMO = LoadMI->
getMMO();
823 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
825 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
829 Preferred = ChoosePreferredUse(
MI, Preferred,
830 MRI.getType(
UseMI.getOperand(0).getReg()),
840 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
858 if (PreviouslyEmitted) {
865 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
866 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
868 EmittedInsns[InsertIntoBB] = NewMI;
874 MI.setDesc(
Builder.getTII().get(LoadOpc));
881 for (
auto *UseMO :
Uses) {
887 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
890 const LLT UseDstTy =
MRI.getType(UseDstReg);
891 if (UseDstReg != ChosenDstReg) {
892 if (Preferred.
Ty == UseDstTy) {
929 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
944 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
947 MI.getOperand(0).setReg(ChosenDstReg);
953 assert(
MI.getOpcode() == TargetOpcode::G_AND);
964 if (
MRI.getType(Dst).isVector())
972 APInt MaskVal = MaybeMask->Value;
981 if (!LoadMI || !
MRI.hasOneNonDBGUse(LoadMI->
getDstReg()))
985 LLT RegTy =
MRI.getType(LoadReg);
993 if (MaskSizeBits > LoadSizeBits.
getValue())
1013 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
1019 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
1023 B.setInstrAndDebugLoc(*LoadMI);
1024 auto &MF =
B.getMF();
1026 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
1027 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1036 "shouldn't consider debug uses");
1044 if (DefOrUse ==
MBB.end())
1046 return &*DefOrUse == &
DefMI;
1052 "shouldn't consider debug uses");
1055 else if (
DefMI.getParent() !=
UseMI.getParent())
1062 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1066 if (
MRI.getType(SrcReg).isVector())
1071 LoadUser = TruncSrc;
1073 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1078 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1080 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1082 if (LoadSizeBits == SizeInBits)
1089 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1090 Builder.buildCopy(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg());
1091 MI.eraseFromParent();
1095 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1096 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1099 LLT RegTy =
MRI.getType(DstReg);
1107 if (!LoadDef || !
MRI.hasOneNonDBGUse(SrcReg))
1110 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1115 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1118 if (NewSizeBits < 8)
1130 if (LoadDef->isSimple())
1132 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1137 {
MRI.getType(LoadDef->getDstReg()),
1138 MRI.getType(LoadDef->getPointerReg())},
1142 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1147 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1148 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1150 unsigned ScalarSizeBits;
1151 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1160 auto &MMO = LoadDef->
getMMO();
1161 Builder.setInstrAndDebugLoc(*LoadDef);
1163 auto PtrInfo = MMO.getPointerInfo();
1164 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1165 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1167 MI.eraseFromParent();
1178 auto *MF =
MI->getMF();
1185 AM.
BaseOffs = CstOff->getSExtValue();
1190 MF->getDataLayout(), AM,
1192 MF->getFunction().getContext()),
1193 MI->getMMO().getAddrSpace());
1198 case TargetOpcode::G_LOAD:
1199 return TargetOpcode::G_INDEXED_LOAD;
1200 case TargetOpcode::G_STORE:
1201 return TargetOpcode::G_INDEXED_STORE;
1202 case TargetOpcode::G_ZEXTLOAD:
1203 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1204 case TargetOpcode::G_SEXTLOAD:
1205 return TargetOpcode::G_INDEXED_SEXTLOAD;
1211bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1221 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1222 OpTys = {PtrTy, Ty, Ty};
1224 OpTys = {Ty, PtrTy};
1226 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1232 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1233 "considered for post-indexing."));
1237 bool &RematOffset)
const {
1247 if (
MRI.hasOneNonDBGUse(
Ptr))
1250 if (!isIndexedLoadStoreLegal(LdSt))
1257 auto *PtrDef =
MRI.getVRegDef(
Ptr);
1259 unsigned NumUsesChecked = 0;
1260 for (
auto &
Use :
MRI.use_nodbg_instructions(
Ptr)) {
1267 if (!PtrAdd ||
MRI.use_nodbg_empty(PtrAdd->getReg(0)))
1272 if (StoredValDef == &
Use)
1275 Offset = PtrAdd->getOffsetReg();
1277 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1283 RematOffset =
false;
1287 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1292 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1293 if (&BasePtrUse == PtrDef)
1299 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1301 isIndexedLoadStoreLegal(*BasePtrLdSt))
1307 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1308 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1311 if (BaseUseUse.getParent() != LdSt.
getParent())
1323 Addr = PtrAdd->getReg(0);
1324 Base = PtrAdd->getBaseReg();
1339 MRI.hasOneNonDBGUse(Addr))
1346 if (!isIndexedLoadStoreLegal(LdSt))
1350 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1355 if (
Base == St->getValueReg())
1360 if (St->getValueReg() == Addr)
1365 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1366 if (AddrUse.getParent() != LdSt.
getParent())
1371 bool RealUse =
false;
1372 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1390 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1400 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1407 if (!LoadMI->isSimple())
1419 const unsigned MaxIter = 20;
1422 if (
II->isLoadFoldBarrier())
1424 if (Iter++ == MaxIter)
1440 int Elt = CVal->getZExtValue();
1453 Register VecPtr = LoadMI->getPointerReg();
1454 LLT PtrTy =
MRI.getType(VecPtr);
1462 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1485 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1500 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1502 if (!MatchInfo.
IsPre &&
1503 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1513 unsigned Opcode =
MI.getOpcode();
1514 bool IsStore = Opcode == TargetOpcode::G_STORE;
1520 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1522 *OldCst->getOperand(1).getCImm());
1523 MatchInfo.
Offset = NewCst.getReg(0);
1526 auto MIB =
Builder.buildInstr(NewOpcode);
1528 MIB.addDef(MatchInfo.
Addr);
1529 MIB.addUse(
MI.getOperand(0).getReg());
1531 MIB.addDef(
MI.getOperand(0).getReg());
1532 MIB.addDef(MatchInfo.
Addr);
1535 MIB.addUse(MatchInfo.
Base);
1536 MIB.addUse(MatchInfo.
Offset);
1537 MIB.addImm(MatchInfo.
IsPre);
1538 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1539 MI.eraseFromParent();
1547 unsigned Opcode =
MI.getOpcode();
1548 bool IsDiv, IsSigned;
1553 case TargetOpcode::G_SDIV:
1554 case TargetOpcode::G_UDIV: {
1556 IsSigned = Opcode == TargetOpcode::G_SDIV;
1559 case TargetOpcode::G_SREM:
1560 case TargetOpcode::G_UREM: {
1562 IsSigned = Opcode == TargetOpcode::G_SREM;
1568 unsigned DivOpcode, RemOpcode, DivremOpcode;
1570 DivOpcode = TargetOpcode::G_SDIV;
1571 RemOpcode = TargetOpcode::G_SREM;
1572 DivremOpcode = TargetOpcode::G_SDIVREM;
1574 DivOpcode = TargetOpcode::G_UDIV;
1575 RemOpcode = TargetOpcode::G_UREM;
1576 DivremOpcode = TargetOpcode::G_UDIVREM;
1594 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1595 if (
MI.getParent() ==
UseMI.getParent() &&
1596 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1597 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1610 unsigned Opcode =
MI.getOpcode();
1611 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1614 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1615 DestDivReg =
MI.getOperand(0).getReg();
1619 DestRemReg =
MI.getOperand(0).getReg();
1623 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1630 Builder.setInstrAndDebugLoc(*FirstInst);
1632 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1633 : TargetOpcode::G_UDIVREM,
1634 {DestDivReg, DestRemReg},
1636 MI.eraseFromParent();
1642 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1659 if (BrIt ==
MBB->begin())
1661 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1663 BrCond = &*std::prev(BrIt);
1664 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1670 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1671 MBB->isLayoutSuccessor(BrCondTarget);
1677 Builder.setInstrAndDebugLoc(*BrCond);
1682 auto True =
Builder.buildConstant(
1688 MI.getOperand(0).setMBB(FallthroughBB);
1703 return Helper.lowerMemcpyInline(
MI) ==
1708 unsigned MaxLen)
const {
1720 switch (
MI.getOpcode()) {
1723 case TargetOpcode::G_FNEG: {
1724 Result.changeSign();
1727 case TargetOpcode::G_FABS: {
1731 case TargetOpcode::G_FPEXT:
1732 case TargetOpcode::G_FPTRUNC: {
1734 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1739 case TargetOpcode::G_FSQRT: {
1743 Result =
APFloat(sqrt(Result.convertToDouble()));
1746 case TargetOpcode::G_FLOG2: {
1766 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1767 MI.eraseFromParent();
1778 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1788 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1801 Type *AccessTy =
nullptr;
1802 auto &MF = *
MI.getMF();
1803 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1806 MF.getFunction().getContext());
1811 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1816 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1818 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1819 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1820 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1821 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1830 unsigned PtrAddFlags =
MI.getFlags();
1831 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1847 MatchInfo.
Flags = Flags;
1853 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1855 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1859 MI.getOperand(1).setReg(MatchInfo.
Base);
1860 MI.getOperand(2).setReg(NewOffset.getReg(0));
1874 unsigned Opcode =
MI.getOpcode();
1875 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1876 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1877 Opcode == TargetOpcode::G_USHLSAT) &&
1878 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1898 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1903 if (Opcode == TargetOpcode::G_USHLSAT &&
1904 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1912 unsigned Opcode =
MI.getOpcode();
1913 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1914 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1915 Opcode == TargetOpcode::G_USHLSAT) &&
1916 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1918 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1919 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1920 auto Imm = MatchInfo.
Imm;
1922 if (Imm >= ScalarSizeInBits) {
1924 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1925 Builder.buildConstant(
MI.getOperand(0), 0);
1926 MI.eraseFromParent();
1931 Imm = ScalarSizeInBits - 1;
1934 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1937 MI.getOperand(1).setReg(MatchInfo.
Reg);
1938 MI.getOperand(2).setReg(NewImm);
1954 unsigned ShiftOpcode =
MI.getOpcode();
1955 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1956 ShiftOpcode == TargetOpcode::G_ASHR ||
1957 ShiftOpcode == TargetOpcode::G_LSHR ||
1958 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1959 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1960 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1963 Register LogicDest =
MI.getOperand(1).getReg();
1964 if (!
MRI.hasOneNonDBGUse(LogicDest))
1968 unsigned LogicOpcode = LogicMI->
getOpcode();
1969 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1970 LogicOpcode != TargetOpcode::G_XOR)
1974 const Register C1 =
MI.getOperand(2).getReg();
1976 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1979 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1983 if (
MI->getOpcode() != ShiftOpcode ||
1984 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1993 ShiftVal = MaybeImmVal->Value.getSExtValue();
2004 if (matchFirstShift(LogicMIOp1, C0Val)) {
2006 MatchInfo.
Shift2 = LogicMIOp1;
2007 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2009 MatchInfo.
Shift2 = LogicMIOp2;
2013 MatchInfo.
ValSum = C0Val + C1Val;
2016 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2019 MatchInfo.
Logic = LogicMI;
2025 unsigned Opcode =
MI.getOpcode();
2026 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2027 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2028 Opcode == TargetOpcode::G_SSHLSAT) &&
2029 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2031 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2032 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2038 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2047 Register Shift2Const =
MI.getOperand(2).getReg();
2049 .buildInstr(Opcode, {DestType},
2059 MI.eraseFromParent();
2064 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2086 auto *SrcDef =
MRI.getVRegDef(SrcReg);
2087 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2088 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2089 LLT SrcTy =
MRI.getType(SrcReg);
2091 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2092 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2093 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {S1, S2});
2101 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2105 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2120 LLT InnerShiftTy =
MRI.getType(InnerShift);
2122 if ((N1C + N001C).ult(InnerShiftSize)) {
2128 if ((N001C + OpSizeInBits) == InnerShiftSize)
2130 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2131 MatchInfo.
Mask =
true;
2141 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2148 if (MatchInfo.
Mask ==
true) {
2156 Builder.buildTrunc(Dst, Shift);
2157 MI.eraseFromParent();
2161 unsigned &ShiftVal)
const {
2162 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2168 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2169 return (
static_cast<int32_t
>(ShiftVal) != -1);
2173 unsigned &ShiftVal)
const {
2174 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2176 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2179 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2180 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2201 auto NegCst =
B.buildConstant(Ty, -Imm);
2203 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2204 MI.getOperand(2).setReg(NegCst.getReg(0));
2206 if (Imm.isMinSignedValue())
2216 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2231 if (!MaybeShiftAmtVal)
2235 LLT SrcTy =
MRI.getType(ExtSrc);
2245 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2246 MatchData.
Reg = ExtSrc;
2247 MatchData.
Imm = ShiftAmt;
2249 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2250 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2251 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2257 int64_t ShiftAmtVal = MatchData.
Imm;
2259 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2260 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2262 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2263 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2264 MI.eraseFromParent();
2271 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2275 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2278 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2279 if (MergedValues[
I] != Unmerge->getReg(
I))
2282 MatchInfo = Unmerge->getSourceReg();
2296 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2297 "Expected an unmerge");
2306 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2307 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2309 if (SrcMergeTy != Dst0Ty && !SameSize)
2313 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2314 Operands.push_back(SrcInstr->getSourceReg(Idx));
2320 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2321 "Expected an unmerge");
2323 "Not enough operands to replace all defs");
2324 unsigned NumElems =
MI.getNumOperands() - 1;
2327 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2328 bool CanReuseInputDirectly = DstTy == SrcTy;
2329 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2330 Register DstReg =
MI.getOperand(Idx).getReg();
2335 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2336 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2337 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2338 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2341 if (CanReuseInputDirectly)
2344 Builder.buildCast(DstReg, SrcReg);
2346 MI.eraseFromParent();
2351 unsigned SrcIdx =
MI.getNumOperands() - 1;
2352 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2354 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2355 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2363 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2366 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2368 Val = Val.
lshr(ShiftAmt);
2376 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2377 "Expected an unmerge");
2379 "Not enough operands to replace all defs");
2380 unsigned NumElems =
MI.getNumOperands() - 1;
2381 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2382 Register DstReg =
MI.getOperand(Idx).getReg();
2383 Builder.buildConstant(DstReg, Csts[Idx]);
2386 MI.eraseFromParent();
2392 unsigned SrcIdx =
MI.getNumOperands() - 1;
2393 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2395 unsigned NumElems =
MI.getNumOperands() - 1;
2396 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2397 Register DstReg =
MI.getOperand(Idx).getReg();
2398 B.buildUndef(DstReg);
2406 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2407 "Expected an unmerge");
2408 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector() ||
2409 MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isVector())
2412 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2413 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2421 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2422 Register Dst0Reg =
MI.getOperand(0).getReg();
2423 Builder.buildTrunc(Dst0Reg, SrcReg);
2424 MI.eraseFromParent();
2428 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2429 "Expected an unmerge");
2430 Register Dst0Reg =
MI.getOperand(0).getReg();
2431 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2437 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2438 LLT SrcTy =
MRI.getType(SrcReg);
2439 if (SrcTy.isVector())
2449 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2454 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2455 "Expected an unmerge");
2457 Register Dst0Reg =
MI.getOperand(0).getReg();
2460 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2462 "Expecting a G_ZEXT");
2465 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2466 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2469 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2472 "ZExt src doesn't fit in destination");
2477 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2479 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2482 MI.eraseFromParent();
2486 unsigned TargetShiftSize,
2487 unsigned &ShiftVal)
const {
2488 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2489 MI.getOpcode() == TargetOpcode::G_LSHR ||
2490 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2492 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2497 unsigned Size = Ty.getSizeInBits();
2498 if (
Size <= TargetShiftSize)
2506 ShiftVal = MaybeImmVal->Value.getSExtValue();
2507 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2514 LLT Ty =
MRI.getType(SrcReg);
2515 unsigned Size = Ty.getSizeInBits();
2516 unsigned HalfSize =
Size / 2;
2517 assert(ShiftVal >= HalfSize);
2521 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2522 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2524 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2525 Register Narrowed = Unmerge.getReg(1);
2532 if (NarrowShiftAmt != 0) {
2533 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2534 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2537 auto Zero =
Builder.buildConstant(HalfTy, 0);
2538 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2539 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2540 Register Narrowed = Unmerge.getReg(0);
2545 if (NarrowShiftAmt != 0) {
2546 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2547 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2550 auto Zero =
Builder.buildConstant(HalfTy, 0);
2551 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2553 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2555 HalfTy, Unmerge.getReg(1),
2556 Builder.buildConstant(HalfTy, HalfSize - 1));
2558 if (ShiftVal == HalfSize) {
2561 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2562 }
else if (ShiftVal ==
Size - 1) {
2570 HalfTy, Unmerge.getReg(1),
2571 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2579 MI.eraseFromParent();
2595 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2597 LLT DstTy =
MRI.getType(DstReg);
2605 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2607 Builder.buildCopy(DstReg, Reg);
2608 MI.eraseFromParent();
2613 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2615 Builder.buildZExtOrTrunc(DstReg, Reg);
2616 MI.eraseFromParent();
2621 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2624 LLT IntTy =
MRI.getType(LHS);
2628 PtrReg.second =
false;
2629 for (
Register SrcReg : {LHS, RHS}) {
2633 LLT PtrTy =
MRI.getType(PtrReg.first);
2638 PtrReg.second =
true;
2650 const bool DoCommute = PtrReg.second;
2655 LLT PtrTy =
MRI.getType(LHS);
2657 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2658 Builder.buildPtrToInt(Dst, PtrAdd);
2659 MI.eraseFromParent();
2663 APInt &NewCst)
const {
2665 Register LHS = PtrAdd.getBaseReg();
2666 Register RHS = PtrAdd.getOffsetReg();
2672 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2675 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2684 APInt &NewCst)
const {
2688 Builder.buildConstant(Dst, NewCst);
2689 PtrAdd.eraseFromParent();
2694 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2699 SrcReg = OriginalSrcReg;
2700 LLT DstTy =
MRI.getType(DstReg);
2708 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2711 LLT DstTy =
MRI.getType(DstReg);
2716 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2717 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2727 if (ShiftSize > 32 && TruncSize < 32)
2740 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2741 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2745 if (!
MRI.hasOneNonDBGUse(SrcReg))
2748 LLT SrcTy =
MRI.getType(SrcReg);
2749 LLT DstTy =
MRI.getType(DstReg);
2758 case TargetOpcode::G_SHL: {
2767 case TargetOpcode::G_LSHR:
2768 case TargetOpcode::G_ASHR: {
2774 for (
auto &
User :
MRI.use_instructions(DstReg))
2775 if (
User.getOpcode() == TargetOpcode::G_STORE)
2779 if (NewShiftTy == SrcTy)
2793 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2796 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2801 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2803 LLT NewShiftTy = MatchInfo.second;
2806 LLT DstTy =
MRI.getType(Dst);
2810 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2814 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2817 if (NewShiftTy == DstTy)
2820 Builder.buildTrunc(Dst, NewShift);
2827 return MO.isReg() &&
2828 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2834 return !MO.isReg() ||
2835 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2840 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2842 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2846 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2847 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2852 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2853 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2859 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2860 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2861 "Expected an insert/extract element op");
2862 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2867 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2875 unsigned &
OpIdx)
const {
2881 OpIdx = Cst->isZero() ? 3 : 2;
2926 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2953 return MO.isReg() && MO.getReg().isPhysical();
2963 return I1->isIdenticalTo(*I2);
2971 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2978 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2990 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2991 MaybeCst->getSExtValue() ==
C;
2998 std::optional<FPValueAndVReg> MaybeCst;
3002 return MaybeCst->Value.isExactlyValue(
C);
3006 unsigned OpIdx)
const {
3007 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3012 MI.eraseFromParent();
3017 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3021 MI.eraseFromParent();
3025 unsigned ConstIdx)
const {
3026 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3027 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3039 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3040 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3041 "This is not a funnel shift operation");
3043 Register ConstReg =
MI.getOperand(3).getReg();
3044 LLT ConstTy =
MRI.getType(ConstReg);
3045 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3048 assert((VRegAndVal) &&
"Value is not a constant");
3051 APInt NewConst = VRegAndVal->Value.
urem(
3056 MI.getOpcode(), {MI.getOperand(0)},
3057 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3059 MI.eraseFromParent();
3063 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3077 unsigned OpIdx)
const {
3084 unsigned OpIdx)
const {
3086 return MO.
isReg() &&
3091 unsigned OpIdx)
const {
3098 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3100 MI.eraseFromParent();
3105 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3107 MI.eraseFromParent();
3111 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3113 MI.eraseFromParent();
3118 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3120 MI.eraseFromParent();
3124 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3126 MI.eraseFromParent();
3130 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3133 Register &NewLHS = std::get<0>(MatchInfo);
3134 Register &NewRHS = std::get<1>(MatchInfo);
3142 NewLHS = MaybeNewLHS;
3146 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3151 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3154 LLT DstTy =
MRI.getType(DstReg);
3163 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3164 TargetOpcode::G_INSERT_VECTOR_ELT)
3170 MatchInfo.
resize(NumElts);
3174 if (IntImm >= NumElts || IntImm < 0)
3176 if (!MatchInfo[IntImm])
3177 MatchInfo[IntImm] = TmpReg;
3181 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3183 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3192 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3199 auto GetUndef = [&]() {
3202 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3210 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3211 MI.eraseFromParent();
3215 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3217 std::tie(SubLHS, SubRHS) = MatchInfo;
3218 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3219 MI.eraseFromParent();
3230 unsigned LogicOpcode =
MI.getOpcode();
3231 assert(LogicOpcode == TargetOpcode::G_AND ||
3232 LogicOpcode == TargetOpcode::G_OR ||
3233 LogicOpcode == TargetOpcode::G_XOR);
3240 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3246 if (!LeftHandInst || !RightHandInst)
3248 unsigned HandOpcode = LeftHandInst->
getOpcode();
3249 if (HandOpcode != RightHandInst->
getOpcode())
3263 if (!XTy.
isValid() || XTy != YTy)
3268 switch (HandOpcode) {
3271 case TargetOpcode::G_ANYEXT:
3272 case TargetOpcode::G_SEXT:
3273 case TargetOpcode::G_ZEXT: {
3277 case TargetOpcode::G_TRUNC: {
3282 LLT DstTy =
MRI.getType(Dst);
3291 case TargetOpcode::G_AND:
3292 case TargetOpcode::G_ASHR:
3293 case TargetOpcode::G_LSHR:
3294 case TargetOpcode::G_SHL: {
3299 ExtraHandOpSrcReg = ZOp.
getReg();
3310 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3321 if (ExtraHandOpSrcReg.
isValid())
3333 "Expected at least one instr to build?");
3335 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3336 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3338 for (
auto &OperandFn : InstrToBuild.OperandFns)
3341 MI.eraseFromParent();
3345 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3346 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3347 int64_t ShlCst, AshrCst;
3353 if (ShlCst != AshrCst)
3356 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3358 MatchInfo = std::make_tuple(Src, ShlCst);
3363 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3364 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3367 std::tie(Src, ShiftAmt) = MatchInfo;
3368 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3369 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3370 MI.eraseFromParent();
3377 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3380 LLT Ty =
MRI.getType(Dst);
3392 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3395 auto Zero =
B.buildConstant(Ty, 0);
3418 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3442 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3449 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3466 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3484 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3491 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3502 unsigned ExtBits =
MI.getOperand(2).getImm();
3503 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3504 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3508 int64_t Cst,
bool IsVector,
bool IsFP) {
3510 return (ScalarSizeBits == 1 && Cst == -1) ||
3533 unsigned NumOperands =
BuildMI->getNumSources();
3541 for (
I = 0;
I < NumOperands; ++
I) {
3542 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3543 auto SrcMIOpc = SrcMI->getOpcode();
3546 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3548 UnmergeMI =
MRI.getVRegDef(SrcMI->getOperand(1).getReg());
3549 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3552 auto UnmergeSrcMI =
MRI.getVRegDef(SrcMI->getOperand(1).getReg());
3553 if (UnmergeMI != UnmergeSrcMI)
3564 for (;
I < NumOperands; ++
I) {
3565 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3566 auto SrcMIOpc = SrcMI->getOpcode();
3568 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3574 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3581 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3582 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3590 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3593 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3605 LLT DstTy =
MRI.getType(DstReg);
3606 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3611 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3616 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3620 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3623 Builder.buildTrunc(DstReg, MidReg);
3624 MI.eraseFromParent();
3629 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3630 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3631 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3639 if (!
MRI.hasOneNonDBGUse(XorSrc))
3649 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3651 if (!
MRI.hasOneNonDBGUse(Reg))
3654 switch (Def->getOpcode()) {
3659 case TargetOpcode::G_ICMP:
3665 case TargetOpcode::G_FCMP:
3671 case TargetOpcode::G_AND:
3672 case TargetOpcode::G_OR:
3678 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3679 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3687 if (Ty.isVector()) {
3692 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3706 for (
Register Reg : RegsToNegate) {
3711 switch (Def->getOpcode()) {
3714 case TargetOpcode::G_ICMP:
3715 case TargetOpcode::G_FCMP: {
3722 case TargetOpcode::G_AND:
3723 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3725 case TargetOpcode::G_OR:
3726 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3733 MI.eraseFromParent();
3737 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3739 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3743 Register SharedReg =
MI.getOperand(2).getReg();
3757 if (!
MRI.hasOneNonDBGUse(AndReg))
3764 return Y == SharedReg;
3768 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3771 std::tie(
X,
Y) = MatchInfo;
3774 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3775 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3776 MI.getOperand(2).setReg(
Y);
3782 Register DstReg = PtrAdd.getReg(0);
3783 LLT Ty =
MRI.getType(DstReg);
3786 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3789 if (Ty.isPointer()) {
3791 return ConstVal && *ConstVal == 0;
3794 assert(Ty.isVector() &&
"Expecting a vector type");
3801 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3802 PtrAdd.eraseFromParent();
3809 Register Pow2Src1 =
MI.getOperand(2).getReg();
3810 LLT Ty =
MRI.getType(DstReg);
3813 auto NegOne =
Builder.buildConstant(Ty, -1);
3814 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3816 MI.eraseFromParent();
3820 unsigned &SelectOpNo)
const {
3830 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3831 !
MRI.hasOneNonDBGUse(LHS)) {
3832 OtherOperandReg = LHS;
3835 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3836 !
MRI.hasOneNonDBGUse(RHS))
3852 unsigned BinOpcode =
MI.getOpcode();
3857 bool CanFoldNonConst =
3858 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3863 if (CanFoldNonConst)
3884 LLT Ty =
MRI.getType(Dst);
3885 unsigned BinOpcode =
MI.getOpcode();
3892 if (SelectOperand == 1) {
3896 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
3898 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
3900 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
3902 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
3905 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
3906 MI.eraseFromParent();
3909std::optional<SmallVector<Register, 8>>
3910CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3911 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3940 const unsigned MaxIter =
3942 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3950 if (!
MRI.hasOneNonDBGUse(OrLHS) || !
MRI.hasOneNonDBGUse(OrRHS))
3951 return std::nullopt;
3967 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
3968 return std::nullopt;
3980static std::optional<std::pair<GZExtLoad *, int64_t>>
3984 "Expected Reg to only have one non-debug use?");
3993 if (Shift % MemSizeInBits != 0)
3994 return std::nullopt;
3999 return std::nullopt;
4001 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4002 return std::nullopt;
4004 return std::make_pair(Load, Shift / MemSizeInBits);
4007std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4008CombinerHelper::findLoadOffsetsForLoadOrCombine(
4011 const unsigned MemSizeInBits)
const {
4014 SmallSetVector<const MachineInstr *, 8> Loads;
4020 GZExtLoad *LowestIdxLoad =
nullptr;
4023 SmallSet<int64_t, 8> SeenIdx;
4027 MachineBasicBlock *
MBB =
nullptr;
4028 const MachineMemOperand *MMO =
nullptr;
4031 GZExtLoad *EarliestLoad =
nullptr;
4034 GZExtLoad *LatestLoad =
nullptr;
4043 for (
auto Reg : RegsToVisit) {
4048 return std::nullopt;
4051 std::tie(Load, DstPos) = *LoadAndPos;
4055 MachineBasicBlock *LoadMBB =
Load->getParent();
4059 return std::nullopt;
4062 auto &LoadMMO =
Load->getMMO();
4066 return std::nullopt;
4073 LoadPtr =
Load->getOperand(1).getReg();
4078 if (!SeenIdx.
insert(Idx).second)
4079 return std::nullopt;
4086 if (BasePtr != LoadPtr)
4087 return std::nullopt;
4089 if (Idx < LowestIdx) {
4091 LowestIdxLoad =
Load;
4098 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4099 return std::nullopt;
4107 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4108 EarliestLoad =
Load;
4109 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4116 "Expected to find a load for each register?");
4117 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4118 LatestLoad &&
"Expected at least two loads?");
4127 const unsigned MaxIter = 20;
4133 if (
MI.isLoadFoldBarrier())
4134 return std::nullopt;
4135 if (Iter++ == MaxIter)
4136 return std::nullopt;
4139 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4145 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4158 LLT Ty =
MRI.getType(Dst);
4164 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4165 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4169 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4176 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4177 if (NarrowMemSizeInBits % 8 != 0)
4190 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4191 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4194 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4201 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4204 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4216 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4217 const unsigned ZeroByteOffset =
4221 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4222 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4223 ZeroOffsetIdx->second != LowestIdx)
4233 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(
Ptr)}, {MMDesc}}))
4247 MIB.setInstrAndDebugLoc(*LatestLoad);
4248 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4249 MIB.buildLoad(LoadDst,
Ptr, *NewMMO);
4251 MIB.buildBSwap(Dst, LoadDst);
4263 if (
MRI.getType(DstReg).isVector())
4267 if (!
MRI.hasOneNonDBGUse(DstReg))
4269 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4271 case TargetOpcode::G_ANYEXT:
4273 case TargetOpcode::G_ZEXT:
4274 case TargetOpcode::G_SEXT:
4281 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4288 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4290 switch (
DefMI->getOpcode()) {
4291 case TargetOpcode::G_LOAD:
4292 case TargetOpcode::G_TRUNC:
4293 case TargetOpcode::G_SEXT:
4294 case TargetOpcode::G_ZEXT:
4295 case TargetOpcode::G_ANYEXT:
4296 case TargetOpcode::G_CONSTANT:
4300 if (InSrcs.
size() > 2)
4314 LLT ExtTy =
MRI.getType(DstReg);
4321 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4322 auto SrcReg =
PHI.getIncomingValue(
I);
4323 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4324 if (!SrcMIs.
insert(SrcMI))
4328 auto *
MBB = SrcMI->getParent();
4330 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4331 InsertPt =
MBB->getFirstNonPHI();
4333 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4336 OldToNewSrcMap[SrcMI] = NewExt;
4341 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4342 NewPhi.addDef(DstReg);
4345 NewPhi.addMBB(MO.getMBB());
4348 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4349 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4357 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4361 LLT SrcTy =
MRI.getType(SrcVec);
4362 if (SrcTy.isScalableVector())
4366 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4369 unsigned VecIdx = Cst->Value.getZExtValue();
4374 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4378 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4379 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4383 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4395 LLT ScalarTy =
MRI.getType(Reg);
4397 LLT DstTy =
MRI.getType(DstReg);
4399 if (ScalarTy != DstTy) {
4401 Builder.buildTrunc(DstReg, Reg);
4402 MI.eraseFromParent();
4410 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4411 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4429 LLT DstTy =
MRI.getType(DstReg);
4434 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4439 unsigned Idx = Cst->getZExtValue();
4442 ExtractedElts.
set(Idx);
4443 SrcDstPairs.emplace_back(
4444 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4447 return ExtractedElts.
all();
4452 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4453 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4454 for (
auto &Pair : SrcDstPairs) {
4455 auto *ExtMI = Pair.second;
4457 ExtMI->eraseFromParent();
4459 MI.eraseFromParent();
4466 MI.eraseFromParent();
4477 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4480 LLT Ty =
MRI.getType(Dst);
4481 unsigned BitWidth = Ty.getScalarSizeInBits();
4483 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4484 unsigned FshOpc = 0;
4495 int64_t CstShlAmt, CstLShrAmt;
4498 CstShlAmt + CstLShrAmt ==
BitWidth) {
4499 FshOpc = TargetOpcode::G_FSHR;
4506 FshOpc = TargetOpcode::G_FSHL;
4512 FshOpc = TargetOpcode::G_FSHR;
4518 LLT AmtTy =
MRI.getType(Amt);
4523 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4530 unsigned Opc =
MI.getOpcode();
4531 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4536 unsigned RotateOpc =
4537 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4542 unsigned Opc =
MI.getOpcode();
4543 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4544 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4546 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4547 : TargetOpcode::G_ROTR));
4548 MI.removeOperand(2);
4554 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4555 MI.getOpcode() == TargetOpcode::G_ROTR);
4557 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4559 bool OutOfRange =
false;
4560 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4562 OutOfRange |= CI->getValue().uge(Bitsize);
4569 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4570 MI.getOpcode() == TargetOpcode::G_ROTR);
4572 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4574 LLT AmtTy =
MRI.getType(Amt);
4575 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4576 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4578 MI.getOperand(2).setReg(Amt);
4583 int64_t &MatchInfo)
const {
4584 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4595 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4596 if (KnownRHS.isUnknown())
4599 std::optional<bool> KnownVal;
4600 if (KnownRHS.isZero()) {
4610 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4620 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4629 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4645 LLT DstTy =
MRI.getType(Dst);
4653 auto KnownLHS =
VT->getKnownBits(LHS);
4654 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4657 LLT LHSTy =
MRI.getType(LHS);
4660 unsigned Op = TargetOpcode::COPY;
4661 if (DstSize != LHSSize)
4662 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4673 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4677 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4683 int64_t AndMaskBits;
4691 if (AndMaskBits & OrMaskBits)
4697 if (
MI.getOperand(1).getReg() == AndMaskReg)
4698 MI.getOperand(2).setReg(AndMaskReg);
4699 MI.getOperand(1).setReg(Src);
4709 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4712 LLT Ty =
MRI.getType(Src);
4714 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4716 int64_t Width =
MI.getOperand(2).getImm();
4724 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4728 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4729 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4730 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4740 LLT Ty =
MRI.getType(Dst);
4744 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4747 int64_t AndImm, LSBImm;
4749 const unsigned Size = Ty.getScalarSizeInBits();
4756 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4757 if (MaybeMask & (MaybeMask + 1))
4766 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4767 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4768 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4776 const unsigned Opcode =
MI.getOpcode();
4777 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4779 const Register Dst =
MI.getOperand(0).getReg();
4781 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4782 ? TargetOpcode::G_SBFX
4783 : TargetOpcode::G_UBFX;
4786 LLT Ty =
MRI.getType(Dst);
4788 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4794 const unsigned Size = Ty.getScalarSizeInBits();
4804 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4808 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4812 const int64_t Pos = ShrAmt - ShlAmt;
4813 const int64_t Width =
Size - ShrAmt;
4816 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4817 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4818 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4826 const unsigned Opcode =
MI.getOpcode();
4827 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4829 const Register Dst =
MI.getOperand(0).getReg();
4830 LLT Ty =
MRI.getType(Dst);
4832 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4845 const unsigned Size = Ty.getScalarSizeInBits();
4846 if (ShrAmt < 0 || ShrAmt >=
Size)
4850 if (0 == (SMask >> ShrAmt)) {
4852 B.buildConstant(Dst, 0);
4858 uint64_t UMask = SMask;
4865 const int64_t Pos = ShrAmt;
4870 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4874 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4875 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4876 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4881bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4885 Register Src1Reg = PtrAdd.getBaseReg();
4890 Register Src2Reg = PtrAdd.getOffsetReg();
4892 if (
MRI.hasOneNonDBGUse(Src1Reg))
4902 const APInt &C1APIntVal = *C1;
4903 const APInt &C2APIntVal = *C2;
4904 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4906 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
4909 MachineInstr *ConvUseMI = &
UseMI;
4910 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4911 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4912 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4914 if (!
MRI.hasOneNonDBGUse(DefReg))
4916 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
4925 TargetLoweringBase::AddrMode AM;
4928 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
4930 PtrAdd.getMF()->getFunction().getContext());
4931 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4932 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4938 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4950 Register Src1Reg =
MI.getOperand(1).getReg();
4951 if (RHS->getOpcode() != TargetOpcode::G_ADD)
4963 unsigned PtrAddFlags =
MI.getFlags();
4964 unsigned AddFlags = RHS->getFlags();
4977 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
4980 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
4982 MI.getOperand(1).setReg(NewBase.getReg(0));
4983 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
4987 return !reassociationCanBreakAddressingModePattern(
MI);
4997 std::optional<ValueAndVReg> LHSCstOff;
5007 unsigned PtrAddFlags =
MI.getFlags();
5008 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5010 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5012 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5026 LHSPtrAdd->moveBefore(&
MI);
5029 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5031 MI.getOperand(2).setReg(NewCst.getReg(0));
5034 Observer.changingInstr(*LHSPtrAdd);
5035 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5036 LHSPtrAdd->setFlags(Flags);
5039 return !reassociationCanBreakAddressingModePattern(
MI);
5050 Register Src2Reg =
MI.getOperand(2).getReg();
5051 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5052 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5065 unsigned PtrAddFlags =
MI.getFlags();
5066 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5079 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5081 MI.getOperand(1).setReg(LHSSrc1);
5082 MI.getOperand(2).setReg(NewCst.getReg(0));
5086 return !reassociationCanBreakAddressingModePattern(
MI);
5124 LLT OpRHSTy =
MRI.getType(OpRHS);
5143 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5144 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5152 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5153 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5166 unsigned Opc =
MI.getOpcode();
5179 APInt &MatchInfo)
const {
5180 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5184 MatchInfo = *MaybeCst;
5192 APInt &MatchInfo)
const {
5198 MatchInfo = *MaybeCst;
5210 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5216 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5217 MI.getOpcode() == TargetOpcode::G_FMAD);
5218 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5235 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5258 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5262 LLT WideTy =
MRI.getType(Dst);
5266 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5282 case TargetOpcode::G_ADD:
5283 case TargetOpcode::G_SUB:
5284 case TargetOpcode::G_MUL:
5285 case TargetOpcode::G_AND:
5286 case TargetOpcode::G_OR:
5287 case TargetOpcode::G_XOR:
5295 auto Mask = Cst->Value;
5300 unsigned NarrowWidth = Mask.countr_one();
5306 auto &MF = *
MI.getMF();
5309 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5310 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5318 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5319 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5321 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5322 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5324 MI.getOperand(1).setReg(Ext.getReg(0));
5332 unsigned Opc =
MI.getOpcode();
5333 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5340 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5341 : TargetOpcode::G_SADDO;
5342 MI.setDesc(
Builder.getTII().get(NewOpc));
5343 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5352 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5353 MI.getOpcode() == TargetOpcode::G_SMULO);
5362 B.buildConstant(Dst, 0);
5363 B.buildConstant(Carry, 0);
5372 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5373 MI.getOpcode() == TargetOpcode::G_SADDE ||
5374 MI.getOpcode() == TargetOpcode::G_USUBE ||
5375 MI.getOpcode() == TargetOpcode::G_SSUBE);
5380 switch (
MI.getOpcode()) {
5381 case TargetOpcode::G_UADDE:
5382 NewOpcode = TargetOpcode::G_UADDO;
5384 case TargetOpcode::G_SADDE:
5385 NewOpcode = TargetOpcode::G_SADDO;
5387 case TargetOpcode::G_USUBE:
5388 NewOpcode = TargetOpcode::G_USUBO;
5390 case TargetOpcode::G_SSUBE:
5391 NewOpcode = TargetOpcode::G_SSUBO;
5395 MI.setDesc(
B.getTII().get(NewOpcode));
5396 MI.removeOperand(4);
5404 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5437 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5438 B.buildSub(Dst, Zero, ReplaceReg);
5447 unsigned Opcode =
MI.getOpcode();
5448 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5450 Register Dst = UDivorRem.getReg(0);
5451 Register LHS = UDivorRem.getReg(1);
5452 Register RHS = UDivorRem.getReg(2);
5453 LLT Ty =
MRI.getType(Dst);
5461 bool UseSRL =
false;
5466 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5468 if (IsSplat && !Factors.
empty()) {
5475 APInt Divisor = CI->getValue();
5484 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5485 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5495 if (Ty.isVector()) {
5496 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5497 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5500 Factor = Factors[0];
5508 return MIB.buildMul(Ty, Res, Factor);
5511 unsigned KnownLeadingZeros =
5512 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5514 bool UseNPQ =
false;
5516 auto BuildUDIVPattern = [&](
const Constant *
C) {
5518 const APInt &Divisor = CI->getValue();
5520 bool SelNPQ =
false;
5522 unsigned PreShift = 0, PostShift = 0;
5527 if (!Divisor.
isOne()) {
5533 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5535 Magic = std::move(magics.
Magic);
5538 "We shouldn't generate an undefined shift!");
5540 "We shouldn't generate an undefined shift!");
5544 SelNPQ = magics.
IsAdd;
5548 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5549 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5551 MIB.buildConstant(ScalarTy,
5556 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5564 assert(Matched &&
"Expected unary predicate match to succeed");
5566 Register PreShift, PostShift, MagicFactor, NPQFactor;
5569 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5570 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5571 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5572 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5575 "Non-build_vector operation should have been a scalar");
5576 PreShift = PreShifts[0];
5577 MagicFactor = MagicFactors[0];
5578 PostShift = PostShifts[0];
5582 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5585 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5588 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5593 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5595 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5597 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5600 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5601 auto One = MIB.buildConstant(Ty, 1);
5602 auto IsOne = MIB.buildICmp(
5604 Ty.isScalar() ?
LLT::scalar(1) : Ty.changeElementSize(1), RHS, One);
5605 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5607 if (Opcode == TargetOpcode::G_UREM) {
5608 auto Prod = MIB.buildMul(Ty, ret, RHS);
5609 return MIB.buildSub(Ty, LHS, Prod);
5615 unsigned Opcode =
MI.getOpcode();
5616 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5619 LLT DstTy =
MRI.getType(Dst);
5621 auto &MF = *
MI.getMF();
5622 AttributeList Attr = MF.getFunction().getAttributes();
5630 if (MF.getFunction().hasMinSize())
5633 if (Opcode == TargetOpcode::G_UDIV &&
5636 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5639 auto *RHSDef =
MRI.getVRegDef(RHS);
5650 {TargetOpcode::G_ICMP,
5654 if (Opcode == TargetOpcode::G_UREM &&
5660 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5669 unsigned Opcode =
MI.getOpcode();
5670 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5673 LLT DstTy =
MRI.getType(Dst);
5677 auto &MF = *
MI.getMF();
5678 AttributeList Attr = MF.getFunction().getAttributes();
5686 if (MF.getFunction().hasMinSize())
5690 if (Opcode == TargetOpcode::G_SDIV &&
5693 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5696 auto *RHSDef =
MRI.getVRegDef(RHS);
5704 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5707 if (Opcode == TargetOpcode::G_SREM &&
5713 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5722 unsigned Opcode =
MI.getOpcode();
5723 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5724 Opcode == TargetOpcode::G_SREM);
5726 Register Dst = SDivorRem.getReg(0);
5727 Register LHS = SDivorRem.getReg(1);
5728 Register RHS = SDivorRem.getReg(2);
5729 LLT Ty =
MRI.getType(Dst);
5736 bool UseSRA =
false;
5742 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5744 if (IsSplat && !ExactFactors.
empty()) {
5746 ExactFactors.
push_back(ExactFactors[0]);
5751 APInt Divisor = CI->getValue();
5761 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5762 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5770 assert(Matched &&
"Expected unary predicate match to succeed");
5773 if (Ty.isVector()) {
5774 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5775 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5777 Shift = ExactShifts[0];
5778 Factor = ExactFactors[0];
5786 return MIB.buildMul(Ty, Res, Factor);
5791 auto BuildSDIVPattern = [&](
const Constant *
C) {
5793 const APInt &Divisor = CI->getValue();
5797 int NumeratorFactor = 0;
5808 NumeratorFactor = 1;
5811 NumeratorFactor = -1;
5814 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5815 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5817 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5818 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5826 assert(Matched &&
"Expected unary predicate match to succeed");
5828 Register MagicFactor, Factor, Shift, ShiftMask;
5831 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5832 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5833 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5834 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5837 "Non-build_vector operation should have been a scalar");
5838 MagicFactor = MagicFactors[0];
5839 Factor = Factors[0];
5841 ShiftMask = ShiftMasks[0];
5845 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5848 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5849 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5852 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5855 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5856 auto T = MIB.buildLShr(Ty, Q, SignShift);
5857 T = MIB.buildAnd(Ty,
T, ShiftMask);
5858 auto ret = MIB.buildAdd(Ty, Q,
T);
5860 if (Opcode == TargetOpcode::G_SREM) {
5861 auto Prod = MIB.buildMul(Ty, ret, RHS);
5862 return MIB.buildSub(Ty, LHS, Prod);
5868 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5869 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5870 "Expected SDIV or UDIV");
5873 auto MatchPow2 = [&](
const Constant *
C) {
5875 return CI && (CI->getValue().isPowerOf2() ||
5876 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5882 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5887 LLT Ty =
MRI.getType(Dst);
5907 unsigned BitWidth = Ty.getScalarSizeInBits();
5908 auto Zero =
Builder.buildConstant(Ty, 0);
5911 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5912 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
5914 auto Sign =
Builder.buildAShr(
5918 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
5924 auto One =
Builder.buildConstant(Ty, 1);
5925 auto MinusOne =
Builder.buildConstant(Ty, -1);
5929 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5930 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
5934 auto Neg =
Builder.buildNeg(Ty, AShr);
5936 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
5937 MI.eraseFromParent();
5941 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5946 LLT Ty =
MRI.getType(Dst);
5949 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5950 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
5951 MI.eraseFromParent();
5955 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
5958 LLT Ty =
MRI.getType(Dst);
5959 LLT RHSTy =
MRI.getType(RHS);
5961 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
5963 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
5978 LLT Ty =
MRI.getType(Dst);
5984 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
5985 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
5986 Builder.buildLShr(Dst, LHS, Trunc);
5987 MI.eraseFromParent();
5994 LLT DstTy =
MRI.getType(Dst);
5995 LLT SrcTy =
MRI.getType(Src);
5997 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
5998 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6000 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6018 Builder.buildTruncSSatS(Dst, MatchInfo);
6019 MI.eraseFromParent();
6026 LLT DstTy =
MRI.getType(Dst);
6027 LLT SrcTy =
MRI.getType(Src);
6029 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6030 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6032 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6050 Builder.buildTruncSSatU(Dst, MatchInfo);
6051 MI.eraseFromParent();
6058 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6059 LLT SrcTy =
MRI.getType(Val);
6061 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6062 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6064 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6073 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6082 unsigned Opc =
MI.getOpcode();
6083 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6084 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6085 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6097 Opc = TargetOpcode::G_FSUB;
6102 Opc = TargetOpcode::G_FADD;
6108 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6109 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6118 MI.setDesc(
B.getTII().get(
Opc));
6119 MI.getOperand(1).setReg(
X);
6120 MI.getOperand(2).setReg(
Y);
6128 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6131 MatchInfo =
MI.getOperand(2).getReg();
6132 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6134 const auto LHSCst = Ty.isVector()
6141 if (LHSCst->Value.isNegZero())
6145 if (LHSCst->Value.isPosZero())
6155 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6162 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6170 MRI.use_instr_nodbg_end()) >
6172 MRI.use_instr_nodbg_end());
6176 bool &AllowFusionGlobally,
6178 bool CanReassociate)
const {
6180 auto *MF =
MI.getMF();
6181 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6183 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6191 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6194 if (!HasFMAD && !HasFMA)
6202 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6209 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6211 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6219 unsigned PreferredFusedOpcode =
6220 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6234 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6235 {LHS.MI->getOperand(1).getReg(),
6236 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6245 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6246 {RHS.MI->getOperand(1).getReg(),
6247 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6258 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6260 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6264 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6269 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6271 unsigned PreferredFusedOpcode =
6272 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6286 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6291 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6292 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6301 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6306 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6307 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6318 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6320 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6328 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6330 unsigned PreferredFusedOpcode =
6331 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6344 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6345 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6346 TargetOpcode::G_FMUL) &&
6347 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6348 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6353 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6354 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6355 TargetOpcode::G_FMUL) &&
6356 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6357 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6364 Register X = FMA->getOperand(1).getReg();
6365 Register Y = FMA->getOperand(2).getReg();
6370 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6371 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6372 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6384 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6386 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6393 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6394 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6400 unsigned PreferredFusedOpcode =
6401 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6414 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6415 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6417 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6419 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6426 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6430 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6435 LHS.MI->getOperand(1).getReg(),
6436 LHS.MI->getOperand(2).getReg(),
B);
6447 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6450 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6455 X =
B.buildFPExt(DstType,
X).getReg(0);
6456 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6467 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6471 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6476 RHS.MI->getOperand(1).getReg(),
6477 RHS.MI->getOperand(2).getReg(),
B);
6488 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6491 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6496 X =
B.buildFPExt(DstType,
X).getReg(0);
6497 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6511 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6513 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6521 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6525 int FirstMulHasFewerUses =
true;
6529 FirstMulHasFewerUses =
false;
6531 unsigned PreferredFusedOpcode =
6532 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6535 if (FirstMulHasFewerUses &&
6539 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6540 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6541 {LHS.MI->getOperand(1).getReg(),
6542 LHS.MI->getOperand(2).getReg(), NegZ});
6551 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6552 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6553 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6564 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6566 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6572 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6574 unsigned PreferredFusedOpcode =
6575 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6586 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6587 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6599 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6612 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6614 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6620 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6622 unsigned PreferredFusedOpcode =
6623 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6635 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6636 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6637 {FpExtX, FpExtY, NegZ});
6649 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6652 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6653 {NegY, FpExtZ, LHSReg});
6664 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6666 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6670 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6671 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6675 unsigned PreferredFusedOpcode =
6676 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6680 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6681 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6682 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6693 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6696 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6699 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6709 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6722 unsigned &IdxToPropagate)
const {
6724 switch (
MI.getOpcode()) {
6727 case TargetOpcode::G_FMINNUM:
6728 case TargetOpcode::G_FMAXNUM:
6729 PropagateNaN =
false;
6731 case TargetOpcode::G_FMINIMUM:
6732 case TargetOpcode::G_FMAXIMUM:
6733 PropagateNaN =
true;
6737 auto MatchNaN = [&](
unsigned Idx) {
6738 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6742 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6746 return MatchNaN(1) || MatchNaN(2);
6754 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6764 if (N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0)))
6777 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6778 if (&U == &
MI || U.getParent() !=
MI.getParent())
6780 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6781 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y) {
6794 return MatchInfo.
size() >= MinUses;
6802 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6803 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6804 MatchInfo[0]->getOperand(2).getReg(),
6805 MatchInfo[0]->getFlags());
6810 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6811 Div->getOperand(0).getReg(),
MI->getFlags());
6812 MI->eraseFromParent();
6817 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6827 Reg == MaybeSameReg;
6829 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
6850 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6859 return MRI.getType(MatchInfo) == DstVecTy;
6862 std::optional<ValueAndVReg> ShiftAmount;
6871 return MRI.getType(MatchInfo) == DstVecTy;
6886 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6893 std::optional<ValueAndVReg> ShiftAmt;
6899 LLT MatchTy =
MRI.getType(MatchInfo);
6900 return ShiftAmt->Value.getZExtValue() == MatchTy.getSizeInBits() &&
6901 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6904unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6906 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6907 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6908 "Expected a NaN behaviour?");
6918 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6919 return TargetOpcode::G_FMAXNUM;
6920 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6921 return TargetOpcode::G_FMAXIMUM;
6922 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6923 return TargetOpcode::G_FMAXNUM;
6924 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6925 return TargetOpcode::G_FMAXIMUM;
6931 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6932 return TargetOpcode::G_FMINNUM;
6933 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6934 return TargetOpcode::G_FMINIMUM;
6935 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6936 return TargetOpcode::G_FMINNUM;
6937 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6939 return TargetOpcode::G_FMINIMUM;
6943CombinerHelper::SelectPatternNaNBehaviour
6945 bool IsOrderedComparison)
const {
6949 if (!LHSSafe && !RHSSafe)
6950 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
6951 if (LHSSafe && RHSSafe)
6952 return SelectPatternNaNBehaviour::RETURNS_ANY;
6955 if (IsOrderedComparison)
6956 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
6957 : SelectPatternNaNBehaviour::RETURNS_OTHER;
6960 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
6961 : SelectPatternNaNBehaviour::RETURNS_NAN;
6970 LLT DstTy =
MRI.getType(Dst);
6983 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
6985 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
6987 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
6990 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
6991 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
6992 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
6993 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
6995 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
6998 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7003 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7008 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7010 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7014 MatchInfo = [=](MachineIRBuilder &
B) {
7015 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7023 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7030 Register TrueVal =
MI.getOperand(2).getReg();
7031 Register FalseVal =
MI.getOperand(3).getReg();
7032 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7037 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7050 if (MatchedSub &&
X != OpLHS)
7058 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7061 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7062 B.buildICmp(Pred, Dst,
Y, Zero);
7069static std::optional<unsigned>
7071 std::optional<int64_t> &Result) {
7072 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7073 Opcode == TargetOpcode::G_ASHR) &&
7074 "Expect G_SHL, G_LSHR or G_ASHR.");
7075 auto SignificantBits = 0;
7077 case TargetOpcode::G_SHL:
7081 case TargetOpcode::G_LSHR:
7085 case TargetOpcode::G_ASHR:
7094 Result = std::nullopt;
7105 Register ShiftVal =
MI.getOperand(1).getReg();
7106 Register ShiftReg =
MI.getOperand(2).getReg();
7107 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7108 auto IsShiftTooBig = [&](
const Constant *
C) {
7113 MatchInfo = std::nullopt;
7117 MI.getOpcode(), MatchInfo);
7118 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7124 unsigned LHSOpndIdx = 1;
7125 unsigned RHSOpndIdx = 2;
7126 switch (
MI.getOpcode()) {
7127 case TargetOpcode::G_UADDO:
7128 case TargetOpcode::G_SADDO:
7129 case TargetOpcode::G_UMULO:
7130 case TargetOpcode::G_SMULO:
7137 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7138 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7143 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7144 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7148 return MRI.getVRegDef(RHS)->getOpcode() !=
7149 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7156 std::optional<FPValueAndVReg> ValAndVReg;
7164 unsigned LHSOpndIdx = 1;
7165 unsigned RHSOpndIdx = 2;
7166 switch (
MI.getOpcode()) {
7167 case TargetOpcode::G_UADDO:
7168 case TargetOpcode::G_SADDO:
7169 case TargetOpcode::G_UMULO:
7170 case TargetOpcode::G_SMULO:
7177 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7178 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7179 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7180 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7184bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7185 LLT SrcTy =
MRI.getType(Src);
7186 if (SrcTy.isFixedVector())
7187 return isConstantSplatVector(Src, 1, AllowUndefs);
7188 if (SrcTy.isScalar()) {
7192 return IConstant && IConstant->Value == 1;
7197bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7198 LLT SrcTy =
MRI.getType(Src);
7200 return isConstantSplatVector(Src, 0, AllowUndefs);
7205 return IConstant && IConstant->Value == 0;
7212bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7213 bool AllowUndefs)
const {
7219 for (
unsigned I = 0;
I < NumSources; ++
I) {
7220 GImplicitDef *ImplicitDef =
7222 if (ImplicitDef && AllowUndefs)
7224 if (ImplicitDef && !AllowUndefs)
7226 std::optional<ValueAndVReg> IConstant =
7228 if (IConstant && IConstant->Value == SplatValue)
7238CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7241 return IConstant->Value;
7245 return std::nullopt;
7248 std::optional<APInt>
Value = std::nullopt;
7249 for (
unsigned I = 0;
I < NumSources; ++
I) {
7250 std::optional<ValueAndVReg> IConstant =
7253 return std::nullopt;
7255 Value = IConstant->Value;
7256 else if (*
Value != IConstant->Value)
7257 return std::nullopt;
7263bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7273 for (
unsigned I = 0;
I < NumSources; ++
I) {
7274 std::optional<ValueAndVReg> IConstant =
7283bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7290 LLT CondTy =
MRI.getType(
Select->getCondReg());
7291 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7301 std::optional<ValueAndVReg> TrueOpt =
7303 std::optional<ValueAndVReg> FalseOpt =
7306 if (!TrueOpt || !FalseOpt)
7309 APInt TrueValue = TrueOpt->Value;
7310 APInt FalseValue = FalseOpt->Value;
7314 MatchInfo = [=](MachineIRBuilder &
B) {
7315 B.setInstrAndDebugLoc(*
Select);
7316 B.buildZExtOrTrunc(Dest,
Cond);
7323 MatchInfo = [=](MachineIRBuilder &
B) {
7324 B.setInstrAndDebugLoc(*
Select);
7325 B.buildSExtOrTrunc(Dest,
Cond);
7332 MatchInfo = [=](MachineIRBuilder &
B) {
7333 B.setInstrAndDebugLoc(*
Select);
7334 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7335 B.buildNot(Inner,
Cond);
7336 B.buildZExtOrTrunc(Dest, Inner);
7343 MatchInfo = [=](MachineIRBuilder &
B) {
7344 B.setInstrAndDebugLoc(*
Select);
7345 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7346 B.buildNot(Inner,
Cond);
7347 B.buildSExtOrTrunc(Dest, Inner);
7353 if (TrueValue - 1 == FalseValue) {
7354 MatchInfo = [=](MachineIRBuilder &
B) {
7355 B.setInstrAndDebugLoc(*
Select);
7356 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7357 B.buildZExtOrTrunc(Inner,
Cond);
7358 B.buildAdd(Dest, Inner, False);
7364 if (TrueValue + 1 == FalseValue) {
7365 MatchInfo = [=](MachineIRBuilder &
B) {
7366 B.setInstrAndDebugLoc(*
Select);
7367 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7368 B.buildSExtOrTrunc(Inner,
Cond);
7369 B.buildAdd(Dest, Inner, False);
7376 MatchInfo = [=](MachineIRBuilder &
B) {
7377 B.setInstrAndDebugLoc(*
Select);
7378 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7379 B.buildZExtOrTrunc(Inner,
Cond);
7382 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7383 B.buildShl(Dest, Inner, ShAmtC, Flags);
7390 MatchInfo = [=](MachineIRBuilder &
B) {
7391 B.setInstrAndDebugLoc(*
Select);
7393 B.buildNot(Not,
Cond);
7394 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7395 B.buildZExtOrTrunc(Inner, Not);
7398 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7399 B.buildShl(Dest, Inner, ShAmtC, Flags);
7406 MatchInfo = [=](MachineIRBuilder &
B) {
7407 B.setInstrAndDebugLoc(*
Select);
7408 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7409 B.buildSExtOrTrunc(Inner,
Cond);
7410 B.buildOr(Dest, Inner, False, Flags);
7417 MatchInfo = [=](MachineIRBuilder &
B) {
7418 B.setInstrAndDebugLoc(*
Select);
7420 B.buildNot(Not,
Cond);
7421 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7422 B.buildSExtOrTrunc(Inner, Not);
7423 B.buildOr(Dest, Inner, True, Flags);
7432bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7439 LLT CondTy =
MRI.getType(
Select->getCondReg());
7440 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7449 if (CondTy != TrueTy)
7454 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7455 MatchInfo = [=](MachineIRBuilder &
B) {
7456 B.setInstrAndDebugLoc(*
Select);
7458 B.buildZExtOrTrunc(Ext,
Cond);
7459 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7460 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7467 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7468 MatchInfo = [=](MachineIRBuilder &
B) {
7469 B.setInstrAndDebugLoc(*
Select);
7471 B.buildZExtOrTrunc(Ext,
Cond);
7472 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7473 B.buildAnd(DstReg, Ext, FreezeTrue);
7479 if (isOneOrOneSplat(False,
true)) {
7480 MatchInfo = [=](MachineIRBuilder &
B) {
7481 B.setInstrAndDebugLoc(*
Select);
7483 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7484 B.buildNot(Inner,
Cond);
7487 B.buildZExtOrTrunc(Ext, Inner);
7488 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7489 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7495 if (isZeroOrZeroSplat(True,
true)) {
7496 MatchInfo = [=](MachineIRBuilder &
B) {
7497 B.setInstrAndDebugLoc(*
Select);
7499 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7500 B.buildNot(Inner,
Cond);
7503 B.buildZExtOrTrunc(Ext, Inner);
7504 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7505 B.buildAnd(DstReg, Ext, FreezeFalse);
7521 LLT DstTy =
MRI.getType(DstReg);
7527 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7536 Register CmpLHS = Cmp->getLHSReg();
7537 Register CmpRHS = Cmp->getRHSReg();
7540 if (True == CmpRHS && False == CmpLHS) {
7548 if (True != CmpLHS || False != CmpRHS)
7588 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7589 Register DestReg =
MI.getOperand(0).getReg();
7590 LLT DestTy =
MRI.getType(DestReg);
7602 if (
isLegal({NewOpc, {DestTy}})) {
7604 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7616 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7619 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7629bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7631 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7632 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7636 unsigned Flags = Logic->
getFlags();
7649 if (!
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7655 std::optional<ValueAndVReg> MaybeC1 =
7659 C1 = MaybeC1->Value;
7661 std::optional<ValueAndVReg> MaybeC2 =
7665 C2 = MaybeC2->Value;
7672 LLT CmpOperandTy =
MRI.getType(R1);
7686 std::optional<APInt> Offset1;
7687 std::optional<APInt> Offset2;
7690 std::optional<ValueAndVReg> MaybeOffset1 =
7693 R1 =
Add->getLHSReg();
7694 Offset1 = MaybeOffset1->Value;
7698 std::optional<ValueAndVReg> MaybeOffset2 =
7701 R2 =
Add->getLHSReg();
7702 Offset2 = MaybeOffset2->Value;
7721 bool CreateMask =
false;
7734 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7747 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7756 MatchInfo = [=](MachineIRBuilder &
B) {
7757 if (CreateMask &&
Offset != 0) {
7758 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7759 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7760 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7761 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7762 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7763 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7764 B.buildZExtOrTrunc(DstReg, ICmp);
7765 }
else if (CreateMask &&
Offset == 0) {
7766 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7767 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7768 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7769 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7770 B.buildZExtOrTrunc(DstReg, ICmp);
7771 }
else if (!CreateMask &&
Offset != 0) {
7772 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7773 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7774 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7775 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7776 B.buildZExtOrTrunc(DstReg, ICmp);
7777 }
else if (!CreateMask &&
Offset == 0) {
7778 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7779 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7780 B.buildZExtOrTrunc(DstReg, ICmp);
7788bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7794 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7806 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7812 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7813 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7814 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7815 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7826 if (LHS0 == RHS1 && LHS1 == RHS0) {
7832 if (LHS0 == RHS0 && LHS1 == RHS1) {
7836 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7838 MatchInfo = [=](MachineIRBuilder &
B) {
7843 auto False =
B.buildConstant(CmpTy, 0);
7844 B.buildZExtOrTrunc(DestReg, False);
7851 B.buildZExtOrTrunc(DestReg, True);
7853 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7854 B.buildZExtOrTrunc(DestReg, Cmp);
7866 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7869 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7878 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7881 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7896 bool IsSigned =
Add->isSigned();
7897 LLT DstTy =
MRI.getType(Dst);
7898 LLT CarryTy =
MRI.getType(Carry);
7901 if (
MRI.use_nodbg_empty(Carry) &&
7904 B.buildAdd(Dst, LHS, RHS);
7905 B.buildUndef(Carry);
7911 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7914 B.buildSAddo(Dst, Carry, RHS, LHS);
7920 B.buildUAddo(Dst, Carry, RHS, LHS);
7925 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7926 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
7932 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7933 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7935 B.buildConstant(Dst, Result);
7936 B.buildConstant(Carry, Overflow);
7944 B.buildCopy(Dst, LHS);
7945 B.buildConstant(Carry, 0);
7954 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
7957 std::optional<APInt> MaybeAddRHS =
7958 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
7961 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
7962 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
7966 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7967 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7973 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7974 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7999 B.buildConstant(Carry, 0);
8006 B.buildAdd(Dst, LHS, RHS);
8007 B.buildConstant(Carry, 1);
8019 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8022 B.buildConstant(Carry, 0);
8038 B.buildConstant(Carry, 0);
8045 B.buildAdd(Dst, LHS, RHS);
8046 B.buildConstant(Carry, 1);
8064 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8070 auto [Dst,
Base] =
MI.getFirst2Regs();
8071 LLT Ty =
MRI.getType(Dst);
8075 Builder.buildFConstant(Dst, 1.0);
8076 MI.removeFromParent();
8088 std::optional<SrcOp> Res;
8090 while (ExpVal > 0) {
8095 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8098 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8105 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8109 MI.eraseFromParent();
8118 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8125 LLT DstTy =
MRI.getType(Dst);
8128 auto Const =
B.buildConstant(DstTy, C1 - C2);
8129 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8141 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8148 LLT DstTy =
MRI.getType(Dst);
8151 auto Const =
B.buildConstant(DstTy, C2 - C1);
8152 B.buildSub(Dst, Const,
Add->getLHSReg());
8164 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8171 LLT DstTy =
MRI.getType(Dst);
8174 auto Const =
B.buildConstant(DstTy, C1 + C2);
8187 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8194 LLT DstTy =
MRI.getType(Dst);
8197 auto Const =
B.buildConstant(DstTy, C1 - C2);
8210 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8217 LLT DstTy =
MRI.getType(Dst);
8220 auto Const =
B.buildConstant(DstTy, C2 - C1);
8221 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8268 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8272 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8275 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8276 LLT SmallBvTy = DstTy;
8280 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8285 {TargetOpcode::G_ANYEXT,
8297 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8298 Ops.push_back(AnyExt.getReg(0));
8316 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8317 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8318 const unsigned NumDstElts = OrigMask.
size();
8319 for (
unsigned i = 0; i != NumDstElts; ++i) {
8320 int Idx = OrigMask[i];
8321 if (Idx >= (
int)NumSrcElems) {
8332 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8333 std::move(NewMask));
8340 const unsigned MaskSize = Mask.size();
8341 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8346 if (Idx < (
int)NumElems)
8347 Mask[
I] = Idx + NumElems;
8349 Mask[
I] = Idx - NumElems;
8359 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8362 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8365 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8366 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8368 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8372 const unsigned NumSrcElems = Src1Ty.isVector() ? Src1Ty.getNumElements() : 1;
8374 bool TouchesSrc1 =
false;
8375 bool TouchesSrc2 =
false;
8376 const unsigned NumElems = Mask.size();
8377 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8381 if (Mask[Idx] < (
int)NumSrcElems)
8387 if (TouchesSrc1 == TouchesSrc2)
8390 Register NewSrc1 = Shuffle.getSrc1Reg();
8393 NewSrc1 = Shuffle.getSrc2Reg();
8398 auto Undef =
B.buildUndef(Src1Ty);
8399 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1, Undef, NewMask);
8413 LLT DstTy =
MRI.getType(Dst);
8414 LLT CarryTy =
MRI.getType(Carry);
8436 B.buildConstant(Carry, 0);
8443 B.buildSub(Dst, LHS, RHS);
8461 B.buildConstant(Carry, 0);
8468 B.buildSub(Dst, LHS, RHS);
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.
mir Rename Register Operands
This file declares the MachineIRBuilder class.
Promote Memory to Register
static unsigned 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.
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 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 matchShuffleToExtract(MachineInstr &MI) const
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
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 matchOrShiftToFunnelShift(MachineInstr &MI, BuildFnTy &MatchInfo) const
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 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 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.
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
void applyCombineShuffleVector(MachineInstr &MI, const ArrayRef< Register > Ops) const
Replace MI with a concat_vectors with Ops.
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.
bool matchCombineShuffleToBuildVector(MachineInstr &MI) const
Replace MI with a build_vector.
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
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
void applyShuffleToExtract(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 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 key_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.
operand_type_match m_Reg()
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false > m_GBuildVector(const LHS &L, const RHS &R)
SpecificConstantOrSplatMatch m_SpecificICstOrSplat(APInt RequestedValue)
Matches a RequestedValue constant or a constant splat of RequestedValue.
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)
SpecificConstantMatch m_SpecificICst(APInt RequestedValue)
Matches a constant equal to RequestedValue.
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)
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.
static constexpr roundingMode rmNearestTiesToEven
static LLVM_ABI const fltSemantics & IEEEdouble() LLVM_READNONE
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