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_FPTRUNC: {
1733 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1738 case TargetOpcode::G_FSQRT: {
1742 Result =
APFloat(sqrt(Result.convertToDouble()));
1745 case TargetOpcode::G_FLOG2: {
1765 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1766 MI.eraseFromParent();
1777 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1787 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1800 Type *AccessTy =
nullptr;
1801 auto &MF = *
MI.getMF();
1802 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1805 MF.getFunction().getContext());
1810 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1815 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1817 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1818 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1819 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1820 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1829 unsigned PtrAddFlags =
MI.getFlags();
1830 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1846 MatchInfo.
Flags = Flags;
1852 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1854 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1858 MI.getOperand(1).setReg(MatchInfo.
Base);
1859 MI.getOperand(2).setReg(NewOffset.getReg(0));
1873 unsigned Opcode =
MI.getOpcode();
1874 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1875 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1876 Opcode == TargetOpcode::G_USHLSAT) &&
1877 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1897 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1902 if (Opcode == TargetOpcode::G_USHLSAT &&
1903 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1911 unsigned Opcode =
MI.getOpcode();
1912 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1913 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1914 Opcode == TargetOpcode::G_USHLSAT) &&
1915 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1917 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1918 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1919 auto Imm = MatchInfo.
Imm;
1921 if (Imm >= ScalarSizeInBits) {
1923 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1924 Builder.buildConstant(
MI.getOperand(0), 0);
1925 MI.eraseFromParent();
1930 Imm = ScalarSizeInBits - 1;
1933 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1936 MI.getOperand(1).setReg(MatchInfo.
Reg);
1937 MI.getOperand(2).setReg(NewImm);
1953 unsigned ShiftOpcode =
MI.getOpcode();
1954 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1955 ShiftOpcode == TargetOpcode::G_ASHR ||
1956 ShiftOpcode == TargetOpcode::G_LSHR ||
1957 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1958 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1959 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1962 Register LogicDest =
MI.getOperand(1).getReg();
1963 if (!
MRI.hasOneNonDBGUse(LogicDest))
1967 unsigned LogicOpcode = LogicMI->
getOpcode();
1968 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1969 LogicOpcode != TargetOpcode::G_XOR)
1973 const Register C1 =
MI.getOperand(2).getReg();
1975 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1978 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1982 if (
MI->getOpcode() != ShiftOpcode ||
1983 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1992 ShiftVal = MaybeImmVal->Value.getSExtValue();
2003 if (matchFirstShift(LogicMIOp1, C0Val)) {
2005 MatchInfo.
Shift2 = LogicMIOp1;
2006 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2008 MatchInfo.
Shift2 = LogicMIOp2;
2012 MatchInfo.
ValSum = C0Val + C1Val;
2015 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2018 MatchInfo.
Logic = LogicMI;
2024 unsigned Opcode =
MI.getOpcode();
2025 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2026 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2027 Opcode == TargetOpcode::G_SSHLSAT) &&
2028 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2030 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2031 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2037 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2046 Register Shift2Const =
MI.getOperand(2).getReg();
2048 .buildInstr(Opcode, {DestType},
2058 MI.eraseFromParent();
2063 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2085 auto *SrcDef =
MRI.getVRegDef(SrcReg);
2086 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2087 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2088 LLT SrcTy =
MRI.getType(SrcReg);
2090 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2091 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2092 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {S1, S2});
2100 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2104 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2119 LLT InnerShiftTy =
MRI.getType(InnerShift);
2121 if ((N1C + N001C).ult(InnerShiftSize)) {
2127 if ((N001C + OpSizeInBits) == InnerShiftSize)
2129 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2130 MatchInfo.
Mask =
true;
2140 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2147 if (MatchInfo.
Mask ==
true) {
2155 Builder.buildTrunc(Dst, Shift);
2156 MI.eraseFromParent();
2160 unsigned &ShiftVal)
const {
2161 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2167 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2168 return (
static_cast<int32_t
>(ShiftVal) != -1);
2172 unsigned &ShiftVal)
const {
2173 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2175 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2178 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2179 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2200 auto NegCst =
B.buildConstant(Ty, -Imm);
2202 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2203 MI.getOperand(2).setReg(NegCst.getReg(0));
2205 if (Imm.isMinSignedValue())
2215 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2230 if (!MaybeShiftAmtVal)
2234 LLT SrcTy =
MRI.getType(ExtSrc);
2244 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2245 MatchData.
Reg = ExtSrc;
2246 MatchData.
Imm = ShiftAmt;
2248 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2249 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2250 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2256 int64_t ShiftAmtVal = MatchData.
Imm;
2258 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2259 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2261 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2262 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2263 MI.eraseFromParent();
2270 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2274 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2277 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2278 if (MergedValues[
I] != Unmerge->getReg(
I))
2281 MatchInfo = Unmerge->getSourceReg();
2295 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2296 "Expected an unmerge");
2305 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2306 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2308 if (SrcMergeTy != Dst0Ty && !SameSize)
2312 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2313 Operands.push_back(SrcInstr->getSourceReg(Idx));
2319 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2320 "Expected an unmerge");
2322 "Not enough operands to replace all defs");
2323 unsigned NumElems =
MI.getNumOperands() - 1;
2326 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2327 bool CanReuseInputDirectly = DstTy == SrcTy;
2328 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2329 Register DstReg =
MI.getOperand(Idx).getReg();
2334 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2335 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2336 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2337 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2340 if (CanReuseInputDirectly)
2343 Builder.buildCast(DstReg, SrcReg);
2345 MI.eraseFromParent();
2350 unsigned SrcIdx =
MI.getNumOperands() - 1;
2351 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2353 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2354 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2362 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2365 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2367 Val = Val.
lshr(ShiftAmt);
2375 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2376 "Expected an unmerge");
2378 "Not enough operands to replace all defs");
2379 unsigned NumElems =
MI.getNumOperands() - 1;
2380 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2381 Register DstReg =
MI.getOperand(Idx).getReg();
2382 Builder.buildConstant(DstReg, Csts[Idx]);
2385 MI.eraseFromParent();
2391 unsigned SrcIdx =
MI.getNumOperands() - 1;
2392 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2394 unsigned NumElems =
MI.getNumOperands() - 1;
2395 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2396 Register DstReg =
MI.getOperand(Idx).getReg();
2397 B.buildUndef(DstReg);
2405 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2406 "Expected an unmerge");
2407 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector() ||
2408 MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isVector())
2411 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2412 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2420 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2421 Register Dst0Reg =
MI.getOperand(0).getReg();
2422 Builder.buildTrunc(Dst0Reg, SrcReg);
2423 MI.eraseFromParent();
2427 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2428 "Expected an unmerge");
2429 Register Dst0Reg =
MI.getOperand(0).getReg();
2430 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2436 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2437 LLT SrcTy =
MRI.getType(SrcReg);
2438 if (SrcTy.isVector())
2448 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2453 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2454 "Expected an unmerge");
2456 Register Dst0Reg =
MI.getOperand(0).getReg();
2459 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2461 "Expecting a G_ZEXT");
2464 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2465 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2468 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2471 "ZExt src doesn't fit in destination");
2476 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2478 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2481 MI.eraseFromParent();
2485 unsigned TargetShiftSize,
2486 unsigned &ShiftVal)
const {
2487 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2488 MI.getOpcode() == TargetOpcode::G_LSHR ||
2489 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2491 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2496 unsigned Size = Ty.getSizeInBits();
2497 if (
Size <= TargetShiftSize)
2505 ShiftVal = MaybeImmVal->Value.getSExtValue();
2506 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2513 LLT Ty =
MRI.getType(SrcReg);
2514 unsigned Size = Ty.getSizeInBits();
2515 unsigned HalfSize =
Size / 2;
2516 assert(ShiftVal >= HalfSize);
2520 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2521 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2523 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2524 Register Narrowed = Unmerge.getReg(1);
2531 if (NarrowShiftAmt != 0) {
2532 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2533 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2536 auto Zero =
Builder.buildConstant(HalfTy, 0);
2537 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2538 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2539 Register Narrowed = Unmerge.getReg(0);
2544 if (NarrowShiftAmt != 0) {
2545 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2546 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2549 auto Zero =
Builder.buildConstant(HalfTy, 0);
2550 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2552 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2554 HalfTy, Unmerge.getReg(1),
2555 Builder.buildConstant(HalfTy, HalfSize - 1));
2557 if (ShiftVal == HalfSize) {
2560 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2561 }
else if (ShiftVal ==
Size - 1) {
2569 HalfTy, Unmerge.getReg(1),
2570 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2578 MI.eraseFromParent();
2594 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2596 LLT DstTy =
MRI.getType(DstReg);
2604 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2606 Builder.buildCopy(DstReg, Reg);
2607 MI.eraseFromParent();
2612 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2614 Builder.buildZExtOrTrunc(DstReg, Reg);
2615 MI.eraseFromParent();
2620 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2623 LLT IntTy =
MRI.getType(LHS);
2627 PtrReg.second =
false;
2628 for (
Register SrcReg : {LHS, RHS}) {
2632 LLT PtrTy =
MRI.getType(PtrReg.first);
2637 PtrReg.second =
true;
2649 const bool DoCommute = PtrReg.second;
2654 LLT PtrTy =
MRI.getType(LHS);
2656 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2657 Builder.buildPtrToInt(Dst, PtrAdd);
2658 MI.eraseFromParent();
2662 APInt &NewCst)
const {
2664 Register LHS = PtrAdd.getBaseReg();
2665 Register RHS = PtrAdd.getOffsetReg();
2671 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2674 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2683 APInt &NewCst)
const {
2687 Builder.buildConstant(Dst, NewCst);
2688 PtrAdd.eraseFromParent();
2693 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2698 SrcReg = OriginalSrcReg;
2699 LLT DstTy =
MRI.getType(DstReg);
2707 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2710 LLT DstTy =
MRI.getType(DstReg);
2715 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2716 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2726 if (ShiftSize > 32 && TruncSize < 32)
2739 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2740 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2744 if (!
MRI.hasOneNonDBGUse(SrcReg))
2747 LLT SrcTy =
MRI.getType(SrcReg);
2748 LLT DstTy =
MRI.getType(DstReg);
2757 case TargetOpcode::G_SHL: {
2766 case TargetOpcode::G_LSHR:
2767 case TargetOpcode::G_ASHR: {
2773 for (
auto &
User :
MRI.use_instructions(DstReg))
2774 if (
User.getOpcode() == TargetOpcode::G_STORE)
2778 if (NewShiftTy == SrcTy)
2792 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2795 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2800 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2802 LLT NewShiftTy = MatchInfo.second;
2805 LLT DstTy =
MRI.getType(Dst);
2809 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2813 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2816 if (NewShiftTy == DstTy)
2819 Builder.buildTrunc(Dst, NewShift);
2826 return MO.isReg() &&
2827 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2833 return !MO.isReg() ||
2834 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2839 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2841 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2845 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2846 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2851 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2852 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2858 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2859 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2860 "Expected an insert/extract element op");
2861 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2866 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2874 unsigned &
OpIdx)
const {
2880 OpIdx = Cst->isZero() ? 3 : 2;
2925 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2952 return MO.isReg() && MO.getReg().isPhysical();
2962 return I1->isIdenticalTo(*I2);
2970 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2977 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2989 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2990 MaybeCst->getSExtValue() ==
C;
2997 std::optional<FPValueAndVReg> MaybeCst;
3001 return MaybeCst->Value.isExactlyValue(
C);
3005 unsigned OpIdx)
const {
3006 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3011 MI.eraseFromParent();
3016 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3020 MI.eraseFromParent();
3024 unsigned ConstIdx)
const {
3025 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3026 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3038 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3039 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3040 "This is not a funnel shift operation");
3042 Register ConstReg =
MI.getOperand(3).getReg();
3043 LLT ConstTy =
MRI.getType(ConstReg);
3044 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3047 assert((VRegAndVal) &&
"Value is not a constant");
3050 APInt NewConst = VRegAndVal->Value.
urem(
3055 MI.getOpcode(), {MI.getOperand(0)},
3056 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3058 MI.eraseFromParent();
3062 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3076 unsigned OpIdx)
const {
3083 unsigned OpIdx)
const {
3085 return MO.
isReg() &&
3090 unsigned OpIdx)
const {
3097 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3099 MI.eraseFromParent();
3104 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3106 MI.eraseFromParent();
3110 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3112 MI.eraseFromParent();
3117 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3119 MI.eraseFromParent();
3123 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3125 MI.eraseFromParent();
3129 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3132 Register &NewLHS = std::get<0>(MatchInfo);
3133 Register &NewRHS = std::get<1>(MatchInfo);
3141 NewLHS = MaybeNewLHS;
3145 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3150 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3153 LLT DstTy =
MRI.getType(DstReg);
3162 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3163 TargetOpcode::G_INSERT_VECTOR_ELT)
3169 MatchInfo.
resize(NumElts);
3173 if (IntImm >= NumElts || IntImm < 0)
3175 if (!MatchInfo[IntImm])
3176 MatchInfo[IntImm] = TmpReg;
3180 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3182 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3191 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3198 auto GetUndef = [&]() {
3201 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3209 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3210 MI.eraseFromParent();
3214 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3216 std::tie(SubLHS, SubRHS) = MatchInfo;
3217 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3218 MI.eraseFromParent();
3229 unsigned LogicOpcode =
MI.getOpcode();
3230 assert(LogicOpcode == TargetOpcode::G_AND ||
3231 LogicOpcode == TargetOpcode::G_OR ||
3232 LogicOpcode == TargetOpcode::G_XOR);
3239 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3245 if (!LeftHandInst || !RightHandInst)
3247 unsigned HandOpcode = LeftHandInst->
getOpcode();
3248 if (HandOpcode != RightHandInst->
getOpcode())
3262 if (!XTy.
isValid() || XTy != YTy)
3267 switch (HandOpcode) {
3270 case TargetOpcode::G_ANYEXT:
3271 case TargetOpcode::G_SEXT:
3272 case TargetOpcode::G_ZEXT: {
3276 case TargetOpcode::G_TRUNC: {
3281 LLT DstTy =
MRI.getType(Dst);
3290 case TargetOpcode::G_AND:
3291 case TargetOpcode::G_ASHR:
3292 case TargetOpcode::G_LSHR:
3293 case TargetOpcode::G_SHL: {
3298 ExtraHandOpSrcReg = ZOp.
getReg();
3309 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3320 if (ExtraHandOpSrcReg.
isValid())
3332 "Expected at least one instr to build?");
3334 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3335 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3337 for (
auto &OperandFn : InstrToBuild.OperandFns)
3340 MI.eraseFromParent();
3344 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3345 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3346 int64_t ShlCst, AshrCst;
3352 if (ShlCst != AshrCst)
3355 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3357 MatchInfo = std::make_tuple(Src, ShlCst);
3362 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3363 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3366 std::tie(Src, ShiftAmt) = MatchInfo;
3367 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3368 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3369 MI.eraseFromParent();
3376 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3379 LLT Ty =
MRI.getType(Dst);
3391 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3394 auto Zero =
B.buildConstant(Ty, 0);
3417 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3441 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3448 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3465 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3483 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3490 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3501 unsigned ExtBits =
MI.getOperand(2).getImm();
3502 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3503 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3507 int64_t Cst,
bool IsVector,
bool IsFP) {
3509 return (ScalarSizeBits == 1 && Cst == -1) ||
3532 unsigned NumOperands =
BuildMI->getNumSources();
3540 for (
I = 0;
I < NumOperands; ++
I) {
3541 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3542 auto SrcMIOpc = SrcMI->getOpcode();
3545 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3547 UnmergeMI =
MRI.getVRegDef(SrcMI->getOperand(1).getReg());
3548 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3551 auto UnmergeSrcMI =
MRI.getVRegDef(SrcMI->getOperand(1).getReg());
3552 if (UnmergeMI != UnmergeSrcMI)
3563 for (;
I < NumOperands; ++
I) {
3564 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3565 auto SrcMIOpc = SrcMI->getOpcode();
3567 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3573 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3580 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3581 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3589 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3592 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3604 LLT DstTy =
MRI.getType(DstReg);
3605 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3610 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3615 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3619 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3622 Builder.buildTrunc(DstReg, MidReg);
3623 MI.eraseFromParent();
3628 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3629 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3630 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3638 if (!
MRI.hasOneNonDBGUse(XorSrc))
3648 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3650 if (!
MRI.hasOneNonDBGUse(Reg))
3653 switch (Def->getOpcode()) {
3658 case TargetOpcode::G_ICMP:
3664 case TargetOpcode::G_FCMP:
3670 case TargetOpcode::G_AND:
3671 case TargetOpcode::G_OR:
3677 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3678 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3686 if (Ty.isVector()) {
3691 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3705 for (
Register Reg : RegsToNegate) {
3710 switch (Def->getOpcode()) {
3713 case TargetOpcode::G_ICMP:
3714 case TargetOpcode::G_FCMP: {
3721 case TargetOpcode::G_AND:
3722 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3724 case TargetOpcode::G_OR:
3725 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3732 MI.eraseFromParent();
3736 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3738 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3742 Register SharedReg =
MI.getOperand(2).getReg();
3756 if (!
MRI.hasOneNonDBGUse(AndReg))
3763 return Y == SharedReg;
3767 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3770 std::tie(
X,
Y) = MatchInfo;
3773 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3774 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3775 MI.getOperand(2).setReg(
Y);
3781 Register DstReg = PtrAdd.getReg(0);
3782 LLT Ty =
MRI.getType(DstReg);
3785 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3788 if (Ty.isPointer()) {
3790 return ConstVal && *ConstVal == 0;
3793 assert(Ty.isVector() &&
"Expecting a vector type");
3800 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3801 PtrAdd.eraseFromParent();
3808 Register Pow2Src1 =
MI.getOperand(2).getReg();
3809 LLT Ty =
MRI.getType(DstReg);
3812 auto NegOne =
Builder.buildConstant(Ty, -1);
3813 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3815 MI.eraseFromParent();
3819 unsigned &SelectOpNo)
const {
3829 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3830 !
MRI.hasOneNonDBGUse(LHS)) {
3831 OtherOperandReg = LHS;
3834 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3835 !
MRI.hasOneNonDBGUse(RHS))
3851 unsigned BinOpcode =
MI.getOpcode();
3856 bool CanFoldNonConst =
3857 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3862 if (CanFoldNonConst)
3883 LLT Ty =
MRI.getType(Dst);
3884 unsigned BinOpcode =
MI.getOpcode();
3891 if (SelectOperand == 1) {
3895 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
3897 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
3899 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
3901 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
3904 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
3905 MI.eraseFromParent();
3908std::optional<SmallVector<Register, 8>>
3909CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3910 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3939 const unsigned MaxIter =
3941 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3949 if (!
MRI.hasOneNonDBGUse(OrLHS) || !
MRI.hasOneNonDBGUse(OrRHS))
3950 return std::nullopt;
3966 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
3967 return std::nullopt;
3979static std::optional<std::pair<GZExtLoad *, int64_t>>
3983 "Expected Reg to only have one non-debug use?");
3992 if (Shift % MemSizeInBits != 0)
3993 return std::nullopt;
3998 return std::nullopt;
4000 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4001 return std::nullopt;
4003 return std::make_pair(Load, Shift / MemSizeInBits);
4006std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4007CombinerHelper::findLoadOffsetsForLoadOrCombine(
4010 const unsigned MemSizeInBits)
const {
4013 SmallSetVector<const MachineInstr *, 8> Loads;
4019 GZExtLoad *LowestIdxLoad =
nullptr;
4022 SmallSet<int64_t, 8> SeenIdx;
4026 MachineBasicBlock *
MBB =
nullptr;
4027 const MachineMemOperand *MMO =
nullptr;
4030 GZExtLoad *EarliestLoad =
nullptr;
4033 GZExtLoad *LatestLoad =
nullptr;
4042 for (
auto Reg : RegsToVisit) {
4047 return std::nullopt;
4050 std::tie(Load, DstPos) = *LoadAndPos;
4054 MachineBasicBlock *LoadMBB =
Load->getParent();
4058 return std::nullopt;
4061 auto &LoadMMO =
Load->getMMO();
4065 return std::nullopt;
4072 LoadPtr =
Load->getOperand(1).getReg();
4077 if (!SeenIdx.
insert(Idx).second)
4078 return std::nullopt;
4085 if (BasePtr != LoadPtr)
4086 return std::nullopt;
4088 if (Idx < LowestIdx) {
4090 LowestIdxLoad =
Load;
4097 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4098 return std::nullopt;
4106 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4107 EarliestLoad =
Load;
4108 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4115 "Expected to find a load for each register?");
4116 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4117 LatestLoad &&
"Expected at least two loads?");
4126 const unsigned MaxIter = 20;
4132 if (
MI.isLoadFoldBarrier())
4133 return std::nullopt;
4134 if (Iter++ == MaxIter)
4135 return std::nullopt;
4138 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4144 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4157 LLT Ty =
MRI.getType(Dst);
4163 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4164 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4168 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4175 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4176 if (NarrowMemSizeInBits % 8 != 0)
4189 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4190 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4193 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4200 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4203 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4215 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4216 const unsigned ZeroByteOffset =
4220 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4221 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4222 ZeroOffsetIdx->second != LowestIdx)
4232 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(
Ptr)}, {MMDesc}}))
4246 MIB.setInstrAndDebugLoc(*LatestLoad);
4247 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4248 MIB.buildLoad(LoadDst,
Ptr, *NewMMO);
4250 MIB.buildBSwap(Dst, LoadDst);
4262 if (
MRI.getType(DstReg).isVector())
4266 if (!
MRI.hasOneNonDBGUse(DstReg))
4268 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4270 case TargetOpcode::G_ANYEXT:
4272 case TargetOpcode::G_ZEXT:
4273 case TargetOpcode::G_SEXT:
4280 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4287 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4289 switch (
DefMI->getOpcode()) {
4290 case TargetOpcode::G_LOAD:
4291 case TargetOpcode::G_TRUNC:
4292 case TargetOpcode::G_SEXT:
4293 case TargetOpcode::G_ZEXT:
4294 case TargetOpcode::G_ANYEXT:
4295 case TargetOpcode::G_CONSTANT:
4299 if (InSrcs.
size() > 2)
4313 LLT ExtTy =
MRI.getType(DstReg);
4320 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4321 auto SrcReg =
PHI.getIncomingValue(
I);
4322 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4323 if (!SrcMIs.
insert(SrcMI))
4327 auto *
MBB = SrcMI->getParent();
4329 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4330 InsertPt =
MBB->getFirstNonPHI();
4332 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4335 OldToNewSrcMap[SrcMI] = NewExt;
4340 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4341 NewPhi.addDef(DstReg);
4344 NewPhi.addMBB(MO.getMBB());
4347 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4348 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4356 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4360 LLT SrcTy =
MRI.getType(SrcVec);
4361 if (SrcTy.isScalableVector())
4365 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4368 unsigned VecIdx = Cst->Value.getZExtValue();
4373 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4377 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4378 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4382 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4394 LLT ScalarTy =
MRI.getType(Reg);
4396 LLT DstTy =
MRI.getType(DstReg);
4398 if (ScalarTy != DstTy) {
4400 Builder.buildTrunc(DstReg, Reg);
4401 MI.eraseFromParent();
4409 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4410 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4428 LLT DstTy =
MRI.getType(DstReg);
4433 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4438 unsigned Idx = Cst->getZExtValue();
4441 ExtractedElts.
set(Idx);
4442 SrcDstPairs.emplace_back(
4443 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4446 return ExtractedElts.
all();
4451 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4452 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4453 for (
auto &Pair : SrcDstPairs) {
4454 auto *ExtMI = Pair.second;
4456 ExtMI->eraseFromParent();
4458 MI.eraseFromParent();
4465 MI.eraseFromParent();
4476 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4479 LLT Ty =
MRI.getType(Dst);
4480 unsigned BitWidth = Ty.getScalarSizeInBits();
4482 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4483 unsigned FshOpc = 0;
4494 int64_t CstShlAmt, CstLShrAmt;
4497 CstShlAmt + CstLShrAmt ==
BitWidth) {
4498 FshOpc = TargetOpcode::G_FSHR;
4505 FshOpc = TargetOpcode::G_FSHL;
4511 FshOpc = TargetOpcode::G_FSHR;
4517 LLT AmtTy =
MRI.getType(Amt);
4522 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4529 unsigned Opc =
MI.getOpcode();
4530 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4535 unsigned RotateOpc =
4536 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4541 unsigned Opc =
MI.getOpcode();
4542 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4543 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4545 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4546 : TargetOpcode::G_ROTR));
4547 MI.removeOperand(2);
4553 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4554 MI.getOpcode() == TargetOpcode::G_ROTR);
4556 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4558 bool OutOfRange =
false;
4559 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4561 OutOfRange |= CI->getValue().uge(Bitsize);
4568 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4569 MI.getOpcode() == TargetOpcode::G_ROTR);
4571 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4573 LLT AmtTy =
MRI.getType(Amt);
4574 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4575 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4577 MI.getOperand(2).setReg(Amt);
4582 int64_t &MatchInfo)
const {
4583 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4594 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4595 if (KnownRHS.isUnknown())
4598 std::optional<bool> KnownVal;
4599 if (KnownRHS.isZero()) {
4609 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4619 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4628 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4644 LLT DstTy =
MRI.getType(Dst);
4652 auto KnownLHS =
VT->getKnownBits(LHS);
4653 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4656 LLT LHSTy =
MRI.getType(LHS);
4659 unsigned Op = TargetOpcode::COPY;
4660 if (DstSize != LHSSize)
4661 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4672 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4676 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4682 int64_t AndMaskBits;
4690 if (AndMaskBits & OrMaskBits)
4696 if (
MI.getOperand(1).getReg() == AndMaskReg)
4697 MI.getOperand(2).setReg(AndMaskReg);
4698 MI.getOperand(1).setReg(Src);
4708 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4711 LLT Ty =
MRI.getType(Src);
4713 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4715 int64_t Width =
MI.getOperand(2).getImm();
4723 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4727 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4728 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4729 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4739 LLT Ty =
MRI.getType(Dst);
4743 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4746 int64_t AndImm, LSBImm;
4748 const unsigned Size = Ty.getScalarSizeInBits();
4755 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4756 if (MaybeMask & (MaybeMask + 1))
4765 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4766 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4767 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4775 const unsigned Opcode =
MI.getOpcode();
4776 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4778 const Register Dst =
MI.getOperand(0).getReg();
4780 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4781 ? TargetOpcode::G_SBFX
4782 : TargetOpcode::G_UBFX;
4785 LLT Ty =
MRI.getType(Dst);
4787 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4793 const unsigned Size = Ty.getScalarSizeInBits();
4803 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4807 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4811 const int64_t Pos = ShrAmt - ShlAmt;
4812 const int64_t Width =
Size - ShrAmt;
4815 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4816 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4817 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4825 const unsigned Opcode =
MI.getOpcode();
4826 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4828 const Register Dst =
MI.getOperand(0).getReg();
4829 LLT Ty =
MRI.getType(Dst);
4831 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4844 const unsigned Size = Ty.getScalarSizeInBits();
4845 if (ShrAmt < 0 || ShrAmt >=
Size)
4849 if (0 == (SMask >> ShrAmt)) {
4851 B.buildConstant(Dst, 0);
4857 uint64_t UMask = SMask;
4864 const int64_t Pos = ShrAmt;
4869 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4873 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4874 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4875 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4880bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4884 Register Src1Reg = PtrAdd.getBaseReg();
4889 Register Src2Reg = PtrAdd.getOffsetReg();
4891 if (
MRI.hasOneNonDBGUse(Src1Reg))
4901 const APInt &C1APIntVal = *C1;
4902 const APInt &C2APIntVal = *C2;
4903 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4905 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
4908 MachineInstr *ConvUseMI = &
UseMI;
4909 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4910 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4911 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4913 if (!
MRI.hasOneNonDBGUse(DefReg))
4915 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
4924 TargetLoweringBase::AddrMode AM;
4927 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
4929 PtrAdd.getMF()->getFunction().getContext());
4930 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4931 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4937 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4949 Register Src1Reg =
MI.getOperand(1).getReg();
4950 if (RHS->getOpcode() != TargetOpcode::G_ADD)
4962 unsigned PtrAddFlags =
MI.getFlags();
4963 unsigned AddFlags = RHS->getFlags();
4976 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
4979 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
4981 MI.getOperand(1).setReg(NewBase.getReg(0));
4982 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
4986 return !reassociationCanBreakAddressingModePattern(
MI);
4996 std::optional<ValueAndVReg> LHSCstOff;
5006 unsigned PtrAddFlags =
MI.getFlags();
5007 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5009 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5011 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5025 LHSPtrAdd->moveBefore(&
MI);
5028 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5030 MI.getOperand(2).setReg(NewCst.getReg(0));
5033 Observer.changingInstr(*LHSPtrAdd);
5034 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5035 LHSPtrAdd->setFlags(Flags);
5038 return !reassociationCanBreakAddressingModePattern(
MI);
5049 Register Src2Reg =
MI.getOperand(2).getReg();
5050 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5051 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5064 unsigned PtrAddFlags =
MI.getFlags();
5065 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5078 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5080 MI.getOperand(1).setReg(LHSSrc1);
5081 MI.getOperand(2).setReg(NewCst.getReg(0));
5085 return !reassociationCanBreakAddressingModePattern(
MI);
5123 LLT OpRHSTy =
MRI.getType(OpRHS);
5142 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5143 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5151 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5152 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5165 unsigned Opc =
MI.getOpcode();
5178 APInt &MatchInfo)
const {
5179 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5183 MatchInfo = *MaybeCst;
5191 APInt &MatchInfo)
const {
5197 MatchInfo = *MaybeCst;
5209 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5215 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5216 MI.getOpcode() == TargetOpcode::G_FMAD);
5217 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5234 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5257 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5261 LLT WideTy =
MRI.getType(Dst);
5265 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5281 case TargetOpcode::G_ADD:
5282 case TargetOpcode::G_SUB:
5283 case TargetOpcode::G_MUL:
5284 case TargetOpcode::G_AND:
5285 case TargetOpcode::G_OR:
5286 case TargetOpcode::G_XOR:
5294 auto Mask = Cst->Value;
5299 unsigned NarrowWidth = Mask.countr_one();
5305 auto &MF = *
MI.getMF();
5308 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5309 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5317 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5318 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5320 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5321 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5323 MI.getOperand(1).setReg(Ext.getReg(0));
5331 unsigned Opc =
MI.getOpcode();
5332 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5339 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5340 : TargetOpcode::G_SADDO;
5341 MI.setDesc(
Builder.getTII().get(NewOpc));
5342 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5351 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5352 MI.getOpcode() == TargetOpcode::G_SMULO);
5361 B.buildConstant(Dst, 0);
5362 B.buildConstant(Carry, 0);
5371 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5372 MI.getOpcode() == TargetOpcode::G_SADDE ||
5373 MI.getOpcode() == TargetOpcode::G_USUBE ||
5374 MI.getOpcode() == TargetOpcode::G_SSUBE);
5379 switch (
MI.getOpcode()) {
5380 case TargetOpcode::G_UADDE:
5381 NewOpcode = TargetOpcode::G_UADDO;
5383 case TargetOpcode::G_SADDE:
5384 NewOpcode = TargetOpcode::G_SADDO;
5386 case TargetOpcode::G_USUBE:
5387 NewOpcode = TargetOpcode::G_USUBO;
5389 case TargetOpcode::G_SSUBE:
5390 NewOpcode = TargetOpcode::G_SSUBO;
5394 MI.setDesc(
B.getTII().get(NewOpcode));
5395 MI.removeOperand(4);
5403 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5436 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5437 B.buildSub(Dst, Zero, ReplaceReg);
5446 unsigned Opcode =
MI.getOpcode();
5447 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5449 Register Dst = UDivorRem.getReg(0);
5450 Register LHS = UDivorRem.getReg(1);
5451 Register RHS = UDivorRem.getReg(2);
5452 LLT Ty =
MRI.getType(Dst);
5460 bool UseSRL =
false;
5465 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5467 if (IsSplat && !Factors.
empty()) {
5474 APInt Divisor = CI->getValue();
5483 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5484 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5494 if (Ty.isVector()) {
5495 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5496 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5499 Factor = Factors[0];
5507 return MIB.buildMul(Ty, Res, Factor);
5510 unsigned KnownLeadingZeros =
5511 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5513 bool UseNPQ =
false;
5515 auto BuildUDIVPattern = [&](
const Constant *
C) {
5517 const APInt &Divisor = CI->getValue();
5519 bool SelNPQ =
false;
5521 unsigned PreShift = 0, PostShift = 0;
5526 if (!Divisor.
isOne()) {
5532 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5534 Magic = std::move(magics.
Magic);
5537 "We shouldn't generate an undefined shift!");
5539 "We shouldn't generate an undefined shift!");
5543 SelNPQ = magics.
IsAdd;
5547 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5548 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5550 MIB.buildConstant(ScalarTy,
5555 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5563 assert(Matched &&
"Expected unary predicate match to succeed");
5565 Register PreShift, PostShift, MagicFactor, NPQFactor;
5568 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5569 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5570 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5571 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5574 "Non-build_vector operation should have been a scalar");
5575 PreShift = PreShifts[0];
5576 MagicFactor = MagicFactors[0];
5577 PostShift = PostShifts[0];
5581 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5584 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5587 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5592 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5594 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5596 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5599 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5600 auto One = MIB.buildConstant(Ty, 1);
5601 auto IsOne = MIB.buildICmp(
5603 Ty.isScalar() ?
LLT::scalar(1) : Ty.changeElementSize(1), RHS, One);
5604 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5606 if (Opcode == TargetOpcode::G_UREM) {
5607 auto Prod = MIB.buildMul(Ty, ret, RHS);
5608 return MIB.buildSub(Ty, LHS, Prod);
5614 unsigned Opcode =
MI.getOpcode();
5615 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5618 LLT DstTy =
MRI.getType(Dst);
5620 auto &MF = *
MI.getMF();
5621 AttributeList Attr = MF.getFunction().getAttributes();
5629 if (MF.getFunction().hasMinSize())
5632 if (Opcode == TargetOpcode::G_UDIV &&
5635 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5638 auto *RHSDef =
MRI.getVRegDef(RHS);
5649 {TargetOpcode::G_ICMP,
5653 if (Opcode == TargetOpcode::G_UREM &&
5659 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5668 unsigned Opcode =
MI.getOpcode();
5669 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5672 LLT DstTy =
MRI.getType(Dst);
5676 auto &MF = *
MI.getMF();
5677 AttributeList Attr = MF.getFunction().getAttributes();
5685 if (MF.getFunction().hasMinSize())
5689 if (Opcode == TargetOpcode::G_SDIV &&
5692 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5695 auto *RHSDef =
MRI.getVRegDef(RHS);
5703 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5706 if (Opcode == TargetOpcode::G_SREM &&
5712 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5721 unsigned Opcode =
MI.getOpcode();
5722 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5723 Opcode == TargetOpcode::G_SREM);
5725 Register Dst = SDivorRem.getReg(0);
5726 Register LHS = SDivorRem.getReg(1);
5727 Register RHS = SDivorRem.getReg(2);
5728 LLT Ty =
MRI.getType(Dst);
5735 bool UseSRA =
false;
5741 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5743 if (IsSplat && !ExactFactors.
empty()) {
5745 ExactFactors.
push_back(ExactFactors[0]);
5750 APInt Divisor = CI->getValue();
5760 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5761 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5769 assert(Matched &&
"Expected unary predicate match to succeed");
5772 if (Ty.isVector()) {
5773 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5774 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5776 Shift = ExactShifts[0];
5777 Factor = ExactFactors[0];
5785 return MIB.buildMul(Ty, Res, Factor);
5790 auto BuildSDIVPattern = [&](
const Constant *
C) {
5792 const APInt &Divisor = CI->getValue();
5796 int NumeratorFactor = 0;
5807 NumeratorFactor = 1;
5810 NumeratorFactor = -1;
5813 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5814 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5816 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5817 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5825 assert(Matched &&
"Expected unary predicate match to succeed");
5827 Register MagicFactor, Factor, Shift, ShiftMask;
5830 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5831 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5832 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5833 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5836 "Non-build_vector operation should have been a scalar");
5837 MagicFactor = MagicFactors[0];
5838 Factor = Factors[0];
5840 ShiftMask = ShiftMasks[0];
5844 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5847 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5848 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5851 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5854 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5855 auto T = MIB.buildLShr(Ty, Q, SignShift);
5856 T = MIB.buildAnd(Ty,
T, ShiftMask);
5857 auto ret = MIB.buildAdd(Ty, Q,
T);
5859 if (Opcode == TargetOpcode::G_SREM) {
5860 auto Prod = MIB.buildMul(Ty, ret, RHS);
5861 return MIB.buildSub(Ty, LHS, Prod);
5867 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5868 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5869 "Expected SDIV or UDIV");
5872 auto MatchPow2 = [&](
const Constant *
C) {
5874 return CI && (CI->getValue().isPowerOf2() ||
5875 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5881 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5886 LLT Ty =
MRI.getType(Dst);
5906 unsigned BitWidth = Ty.getScalarSizeInBits();
5907 auto Zero =
Builder.buildConstant(Ty, 0);
5910 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5911 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
5913 auto Sign =
Builder.buildAShr(
5917 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
5923 auto One =
Builder.buildConstant(Ty, 1);
5924 auto MinusOne =
Builder.buildConstant(Ty, -1);
5928 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5929 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
5933 auto Neg =
Builder.buildNeg(Ty, AShr);
5935 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
5936 MI.eraseFromParent();
5940 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5945 LLT Ty =
MRI.getType(Dst);
5948 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5949 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
5950 MI.eraseFromParent();
5954 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
5957 LLT Ty =
MRI.getType(Dst);
5958 LLT RHSTy =
MRI.getType(RHS);
5960 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
5962 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
5977 LLT Ty =
MRI.getType(Dst);
5983 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
5984 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
5985 Builder.buildLShr(Dst, LHS, Trunc);
5986 MI.eraseFromParent();
5993 LLT DstTy =
MRI.getType(Dst);
5994 LLT SrcTy =
MRI.getType(Src);
5996 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
5997 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
5999 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6017 Builder.buildTruncSSatS(Dst, MatchInfo);
6018 MI.eraseFromParent();
6025 LLT DstTy =
MRI.getType(Dst);
6026 LLT SrcTy =
MRI.getType(Src);
6028 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6029 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6031 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6049 Builder.buildTruncSSatU(Dst, MatchInfo);
6050 MI.eraseFromParent();
6057 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6058 LLT SrcTy =
MRI.getType(Val);
6060 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6061 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6063 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6072 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6081 unsigned Opc =
MI.getOpcode();
6082 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6083 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6084 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6096 Opc = TargetOpcode::G_FSUB;
6101 Opc = TargetOpcode::G_FADD;
6107 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6108 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6117 MI.setDesc(
B.getTII().get(
Opc));
6118 MI.getOperand(1).setReg(
X);
6119 MI.getOperand(2).setReg(
Y);
6127 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6130 MatchInfo =
MI.getOperand(2).getReg();
6131 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6133 const auto LHSCst = Ty.isVector()
6140 if (LHSCst->Value.isNegZero())
6144 if (LHSCst->Value.isPosZero())
6154 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6161 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6169 MRI.use_instr_nodbg_end()) >
6171 MRI.use_instr_nodbg_end());
6175 bool &AllowFusionGlobally,
6177 bool CanReassociate)
const {
6179 auto *MF =
MI.getMF();
6180 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6182 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6190 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6193 if (!HasFMAD && !HasFMA)
6201 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6208 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6210 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6218 unsigned PreferredFusedOpcode =
6219 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6233 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6234 {LHS.MI->getOperand(1).getReg(),
6235 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6244 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6245 {RHS.MI->getOperand(1).getReg(),
6246 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6257 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6259 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6263 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6268 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6270 unsigned PreferredFusedOpcode =
6271 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6285 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6290 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6291 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6300 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6305 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6306 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6317 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6319 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6327 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6329 unsigned PreferredFusedOpcode =
6330 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6343 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6344 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6345 TargetOpcode::G_FMUL) &&
6346 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6347 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6352 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6353 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6354 TargetOpcode::G_FMUL) &&
6355 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6356 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6363 Register X = FMA->getOperand(1).getReg();
6364 Register Y = FMA->getOperand(2).getReg();
6369 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6370 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6371 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6383 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6385 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6392 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6393 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6399 unsigned PreferredFusedOpcode =
6400 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6413 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6414 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6416 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6418 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6425 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6429 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6434 LHS.MI->getOperand(1).getReg(),
6435 LHS.MI->getOperand(2).getReg(),
B);
6446 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6449 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6454 X =
B.buildFPExt(DstType,
X).getReg(0);
6455 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6466 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6470 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6475 RHS.MI->getOperand(1).getReg(),
6476 RHS.MI->getOperand(2).getReg(),
B);
6487 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6490 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6495 X =
B.buildFPExt(DstType,
X).getReg(0);
6496 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6510 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6512 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6520 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6524 int FirstMulHasFewerUses =
true;
6528 FirstMulHasFewerUses =
false;
6530 unsigned PreferredFusedOpcode =
6531 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6534 if (FirstMulHasFewerUses &&
6538 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6539 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6540 {LHS.MI->getOperand(1).getReg(),
6541 LHS.MI->getOperand(2).getReg(), NegZ});
6550 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6551 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6552 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6563 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6565 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6571 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6573 unsigned PreferredFusedOpcode =
6574 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6585 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6586 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6598 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6611 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6613 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6619 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6621 unsigned PreferredFusedOpcode =
6622 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6634 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6635 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6636 {FpExtX, FpExtY, NegZ});
6648 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6651 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6652 {NegY, FpExtZ, LHSReg});
6663 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6665 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6669 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6670 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6674 unsigned PreferredFusedOpcode =
6675 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6679 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6680 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6681 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6692 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6695 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6698 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6708 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6721 unsigned &IdxToPropagate)
const {
6723 switch (
MI.getOpcode()) {
6726 case TargetOpcode::G_FMINNUM:
6727 case TargetOpcode::G_FMAXNUM:
6728 PropagateNaN =
false;
6730 case TargetOpcode::G_FMINIMUM:
6731 case TargetOpcode::G_FMAXIMUM:
6732 PropagateNaN =
true;
6736 auto MatchNaN = [&](
unsigned Idx) {
6737 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6741 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6745 return MatchNaN(1) || MatchNaN(2);
6749 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6759 Reg == MaybeSameReg;
6761 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
6782 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6791 return MRI.getType(MatchInfo) == DstVecTy;
6794 std::optional<ValueAndVReg> ShiftAmount;
6803 return MRI.getType(MatchInfo) == DstVecTy;
6818 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6825 std::optional<ValueAndVReg> ShiftAmt;
6831 LLT MatchTy =
MRI.getType(MatchInfo);
6832 return ShiftAmt->Value.getZExtValue() == MatchTy.getSizeInBits() &&
6833 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6836unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6838 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6839 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6840 "Expected a NaN behaviour?");
6850 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6851 return TargetOpcode::G_FMAXNUM;
6852 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6853 return TargetOpcode::G_FMAXIMUM;
6854 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6855 return TargetOpcode::G_FMAXNUM;
6856 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6857 return TargetOpcode::G_FMAXIMUM;
6863 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6864 return TargetOpcode::G_FMINNUM;
6865 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6866 return TargetOpcode::G_FMINIMUM;
6867 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6868 return TargetOpcode::G_FMINNUM;
6869 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6871 return TargetOpcode::G_FMINIMUM;
6875CombinerHelper::SelectPatternNaNBehaviour
6877 bool IsOrderedComparison)
const {
6881 if (!LHSSafe && !RHSSafe)
6882 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
6883 if (LHSSafe && RHSSafe)
6884 return SelectPatternNaNBehaviour::RETURNS_ANY;
6887 if (IsOrderedComparison)
6888 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
6889 : SelectPatternNaNBehaviour::RETURNS_OTHER;
6892 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
6893 : SelectPatternNaNBehaviour::RETURNS_NAN;
6902 LLT DstTy =
MRI.getType(Dst);
6915 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
6917 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
6919 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
6922 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
6923 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
6924 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
6925 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
6927 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
6930 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
6935 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
6940 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
6942 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
6946 MatchInfo = [=](MachineIRBuilder &
B) {
6947 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
6955 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
6962 Register TrueVal =
MI.getOperand(2).getReg();
6963 Register FalseVal =
MI.getOperand(3).getReg();
6964 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
6969 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
6982 if (MatchedSub &&
X != OpLHS)
6990 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
6993 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
6994 B.buildICmp(Pred, Dst,
Y, Zero);
7001static std::optional<unsigned>
7003 std::optional<int64_t> &Result) {
7004 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7005 Opcode == TargetOpcode::G_ASHR) &&
7006 "Expect G_SHL, G_LSHR or G_ASHR.");
7007 auto SignificantBits = 0;
7009 case TargetOpcode::G_SHL:
7013 case TargetOpcode::G_LSHR:
7017 case TargetOpcode::G_ASHR:
7026 Result = std::nullopt;
7037 Register ShiftVal =
MI.getOperand(1).getReg();
7038 Register ShiftReg =
MI.getOperand(2).getReg();
7039 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7040 auto IsShiftTooBig = [&](
const Constant *
C) {
7045 MatchInfo = std::nullopt;
7049 MI.getOpcode(), MatchInfo);
7050 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7056 unsigned LHSOpndIdx = 1;
7057 unsigned RHSOpndIdx = 2;
7058 switch (
MI.getOpcode()) {
7059 case TargetOpcode::G_UADDO:
7060 case TargetOpcode::G_SADDO:
7061 case TargetOpcode::G_UMULO:
7062 case TargetOpcode::G_SMULO:
7069 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7070 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7075 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7076 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7080 return MRI.getVRegDef(RHS)->getOpcode() !=
7081 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7088 std::optional<FPValueAndVReg> ValAndVReg;
7096 unsigned LHSOpndIdx = 1;
7097 unsigned RHSOpndIdx = 2;
7098 switch (
MI.getOpcode()) {
7099 case TargetOpcode::G_UADDO:
7100 case TargetOpcode::G_SADDO:
7101 case TargetOpcode::G_UMULO:
7102 case TargetOpcode::G_SMULO:
7109 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7110 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7111 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7112 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7116bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7117 LLT SrcTy =
MRI.getType(Src);
7118 if (SrcTy.isFixedVector())
7119 return isConstantSplatVector(Src, 1, AllowUndefs);
7120 if (SrcTy.isScalar()) {
7124 return IConstant && IConstant->Value == 1;
7129bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7130 LLT SrcTy =
MRI.getType(Src);
7132 return isConstantSplatVector(Src, 0, AllowUndefs);
7137 return IConstant && IConstant->Value == 0;
7144bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7145 bool AllowUndefs)
const {
7151 for (
unsigned I = 0;
I < NumSources; ++
I) {
7152 GImplicitDef *ImplicitDef =
7154 if (ImplicitDef && AllowUndefs)
7156 if (ImplicitDef && !AllowUndefs)
7158 std::optional<ValueAndVReg> IConstant =
7160 if (IConstant && IConstant->Value == SplatValue)
7170CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7173 return IConstant->Value;
7177 return std::nullopt;
7180 std::optional<APInt>
Value = std::nullopt;
7181 for (
unsigned I = 0;
I < NumSources; ++
I) {
7182 std::optional<ValueAndVReg> IConstant =
7185 return std::nullopt;
7187 Value = IConstant->Value;
7188 else if (*
Value != IConstant->Value)
7189 return std::nullopt;
7195bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7205 for (
unsigned I = 0;
I < NumSources; ++
I) {
7206 std::optional<ValueAndVReg> IConstant =
7215bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7222 LLT CondTy =
MRI.getType(
Select->getCondReg());
7223 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7233 std::optional<ValueAndVReg> TrueOpt =
7235 std::optional<ValueAndVReg> FalseOpt =
7238 if (!TrueOpt || !FalseOpt)
7241 APInt TrueValue = TrueOpt->Value;
7242 APInt FalseValue = FalseOpt->Value;
7246 MatchInfo = [=](MachineIRBuilder &
B) {
7247 B.setInstrAndDebugLoc(*
Select);
7248 B.buildZExtOrTrunc(Dest,
Cond);
7255 MatchInfo = [=](MachineIRBuilder &
B) {
7256 B.setInstrAndDebugLoc(*
Select);
7257 B.buildSExtOrTrunc(Dest,
Cond);
7264 MatchInfo = [=](MachineIRBuilder &
B) {
7265 B.setInstrAndDebugLoc(*
Select);
7266 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7267 B.buildNot(Inner,
Cond);
7268 B.buildZExtOrTrunc(Dest, Inner);
7275 MatchInfo = [=](MachineIRBuilder &
B) {
7276 B.setInstrAndDebugLoc(*
Select);
7277 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7278 B.buildNot(Inner,
Cond);
7279 B.buildSExtOrTrunc(Dest, Inner);
7285 if (TrueValue - 1 == FalseValue) {
7286 MatchInfo = [=](MachineIRBuilder &
B) {
7287 B.setInstrAndDebugLoc(*
Select);
7288 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7289 B.buildZExtOrTrunc(Inner,
Cond);
7290 B.buildAdd(Dest, Inner, False);
7296 if (TrueValue + 1 == FalseValue) {
7297 MatchInfo = [=](MachineIRBuilder &
B) {
7298 B.setInstrAndDebugLoc(*
Select);
7299 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7300 B.buildSExtOrTrunc(Inner,
Cond);
7301 B.buildAdd(Dest, Inner, False);
7308 MatchInfo = [=](MachineIRBuilder &
B) {
7309 B.setInstrAndDebugLoc(*
Select);
7310 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7311 B.buildZExtOrTrunc(Inner,
Cond);
7314 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7315 B.buildShl(Dest, Inner, ShAmtC, Flags);
7322 MatchInfo = [=](MachineIRBuilder &
B) {
7323 B.setInstrAndDebugLoc(*
Select);
7325 B.buildNot(Not,
Cond);
7326 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7327 B.buildZExtOrTrunc(Inner, Not);
7330 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7331 B.buildShl(Dest, Inner, ShAmtC, Flags);
7338 MatchInfo = [=](MachineIRBuilder &
B) {
7339 B.setInstrAndDebugLoc(*
Select);
7340 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7341 B.buildSExtOrTrunc(Inner,
Cond);
7342 B.buildOr(Dest, Inner, False, Flags);
7349 MatchInfo = [=](MachineIRBuilder &
B) {
7350 B.setInstrAndDebugLoc(*
Select);
7352 B.buildNot(Not,
Cond);
7353 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7354 B.buildSExtOrTrunc(Inner, Not);
7355 B.buildOr(Dest, Inner, True, Flags);
7364bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7371 LLT CondTy =
MRI.getType(
Select->getCondReg());
7372 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7381 if (CondTy != TrueTy)
7386 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7387 MatchInfo = [=](MachineIRBuilder &
B) {
7388 B.setInstrAndDebugLoc(*
Select);
7390 B.buildZExtOrTrunc(Ext,
Cond);
7391 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7392 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7399 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7400 MatchInfo = [=](MachineIRBuilder &
B) {
7401 B.setInstrAndDebugLoc(*
Select);
7403 B.buildZExtOrTrunc(Ext,
Cond);
7404 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7405 B.buildAnd(DstReg, Ext, FreezeTrue);
7411 if (isOneOrOneSplat(False,
true)) {
7412 MatchInfo = [=](MachineIRBuilder &
B) {
7413 B.setInstrAndDebugLoc(*
Select);
7415 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7416 B.buildNot(Inner,
Cond);
7419 B.buildZExtOrTrunc(Ext, Inner);
7420 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7421 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7427 if (isZeroOrZeroSplat(True,
true)) {
7428 MatchInfo = [=](MachineIRBuilder &
B) {
7429 B.setInstrAndDebugLoc(*
Select);
7431 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7432 B.buildNot(Inner,
Cond);
7435 B.buildZExtOrTrunc(Ext, Inner);
7436 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7437 B.buildAnd(DstReg, Ext, FreezeFalse);
7453 LLT DstTy =
MRI.getType(DstReg);
7459 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7468 Register CmpLHS = Cmp->getLHSReg();
7469 Register CmpRHS = Cmp->getRHSReg();
7472 if (True == CmpRHS && False == CmpLHS) {
7480 if (True != CmpLHS || False != CmpRHS)
7520 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7521 Register DestReg =
MI.getOperand(0).getReg();
7522 LLT DestTy =
MRI.getType(DestReg);
7534 if (
isLegal({NewOpc, {DestTy}})) {
7536 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7548 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7551 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7561bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7563 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7564 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7568 unsigned Flags = Logic->
getFlags();
7581 if (!
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7587 std::optional<ValueAndVReg> MaybeC1 =
7591 C1 = MaybeC1->Value;
7593 std::optional<ValueAndVReg> MaybeC2 =
7597 C2 = MaybeC2->Value;
7604 LLT CmpOperandTy =
MRI.getType(R1);
7618 std::optional<APInt> Offset1;
7619 std::optional<APInt> Offset2;
7622 std::optional<ValueAndVReg> MaybeOffset1 =
7625 R1 =
Add->getLHSReg();
7626 Offset1 = MaybeOffset1->Value;
7630 std::optional<ValueAndVReg> MaybeOffset2 =
7633 R2 =
Add->getLHSReg();
7634 Offset2 = MaybeOffset2->Value;
7653 bool CreateMask =
false;
7666 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7679 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7688 MatchInfo = [=](MachineIRBuilder &
B) {
7689 if (CreateMask &&
Offset != 0) {
7690 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7691 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7692 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7693 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7694 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7695 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7696 B.buildZExtOrTrunc(DstReg, ICmp);
7697 }
else if (CreateMask &&
Offset == 0) {
7698 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7699 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7700 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7701 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7702 B.buildZExtOrTrunc(DstReg, ICmp);
7703 }
else if (!CreateMask &&
Offset != 0) {
7704 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7705 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7706 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7707 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7708 B.buildZExtOrTrunc(DstReg, ICmp);
7709 }
else if (!CreateMask &&
Offset == 0) {
7710 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7711 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7712 B.buildZExtOrTrunc(DstReg, ICmp);
7720bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7726 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7738 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7744 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7745 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7746 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7747 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7758 if (LHS0 == RHS1 && LHS1 == RHS0) {
7764 if (LHS0 == RHS0 && LHS1 == RHS1) {
7768 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7770 MatchInfo = [=](MachineIRBuilder &
B) {
7775 auto False =
B.buildConstant(CmpTy, 0);
7776 B.buildZExtOrTrunc(DestReg, False);
7783 B.buildZExtOrTrunc(DestReg, True);
7785 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7786 B.buildZExtOrTrunc(DestReg, Cmp);
7798 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7801 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7810 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7813 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7828 bool IsSigned =
Add->isSigned();
7829 LLT DstTy =
MRI.getType(Dst);
7830 LLT CarryTy =
MRI.getType(Carry);
7833 if (
MRI.use_nodbg_empty(Carry) &&
7836 B.buildAdd(Dst, LHS, RHS);
7837 B.buildUndef(Carry);
7843 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7846 B.buildSAddo(Dst, Carry, RHS, LHS);
7852 B.buildUAddo(Dst, Carry, RHS, LHS);
7857 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7858 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
7864 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7865 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7867 B.buildConstant(Dst, Result);
7868 B.buildConstant(Carry, Overflow);
7876 B.buildCopy(Dst, LHS);
7877 B.buildConstant(Carry, 0);
7886 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
7889 std::optional<APInt> MaybeAddRHS =
7890 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
7893 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
7894 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
7898 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7899 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7905 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7906 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7931 B.buildConstant(Carry, 0);
7938 B.buildAdd(Dst, LHS, RHS);
7939 B.buildConstant(Carry, 1);
7951 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
7954 B.buildConstant(Carry, 0);
7970 B.buildConstant(Carry, 0);
7977 B.buildAdd(Dst, LHS, RHS);
7978 B.buildConstant(Carry, 1);
7996 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8002 auto [Dst,
Base] =
MI.getFirst2Regs();
8003 LLT Ty =
MRI.getType(Dst);
8007 Builder.buildFConstant(Dst, 1.0);
8008 MI.removeFromParent();
8020 std::optional<SrcOp> Res;
8022 while (ExpVal > 0) {
8027 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8030 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8037 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8041 MI.eraseFromParent();
8050 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8057 LLT DstTy =
MRI.getType(Dst);
8060 auto Const =
B.buildConstant(DstTy, C1 - C2);
8061 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8073 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8080 LLT DstTy =
MRI.getType(Dst);
8083 auto Const =
B.buildConstant(DstTy, C2 - C1);
8084 B.buildSub(Dst, Const,
Add->getLHSReg());
8096 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8103 LLT DstTy =
MRI.getType(Dst);
8106 auto Const =
B.buildConstant(DstTy, C1 + C2);
8119 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8126 LLT DstTy =
MRI.getType(Dst);
8129 auto Const =
B.buildConstant(DstTy, C1 - C2);
8142 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8149 LLT DstTy =
MRI.getType(Dst);
8152 auto Const =
B.buildConstant(DstTy, C2 - C1);
8153 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8200 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8204 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8207 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8208 LLT SmallBvTy = DstTy;
8212 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8217 {TargetOpcode::G_ANYEXT,
8229 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8230 Ops.push_back(AnyExt.getReg(0));
8248 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8249 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8250 const unsigned NumDstElts = OrigMask.
size();
8251 for (
unsigned i = 0; i != NumDstElts; ++i) {
8252 int Idx = OrigMask[i];
8253 if (Idx >= (
int)NumSrcElems) {
8264 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8265 std::move(NewMask));
8272 const unsigned MaskSize = Mask.size();
8273 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8278 if (Idx < (
int)NumElems)
8279 Mask[
I] = Idx + NumElems;
8281 Mask[
I] = Idx - NumElems;
8291 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8294 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8297 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8298 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8300 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8304 const unsigned NumSrcElems = Src1Ty.isVector() ? Src1Ty.getNumElements() : 1;
8306 bool TouchesSrc1 =
false;
8307 bool TouchesSrc2 =
false;
8308 const unsigned NumElems = Mask.size();
8309 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8313 if (Mask[Idx] < (
int)NumSrcElems)
8319 if (TouchesSrc1 == TouchesSrc2)
8322 Register NewSrc1 = Shuffle.getSrc1Reg();
8325 NewSrc1 = Shuffle.getSrc2Reg();
8330 auto Undef =
B.buildUndef(Src1Ty);
8331 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1, Undef, NewMask);
8345 LLT DstTy =
MRI.getType(Dst);
8346 LLT CarryTy =
MRI.getType(Carry);
8368 B.buildConstant(Carry, 0);
8375 B.buildSub(Dst, LHS, RHS);
8393 B.buildConstant(Carry, 0);
8400 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 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 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
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 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...
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