44#define DEBUG_TYPE "gi-combiner"
47using namespace MIPatternMatch;
53 cl::desc(
"Force all indexed operations to be "
54 "legal for the GlobalISel combiner"));
60 : Builder(
B),
MRI(Builder.getMF().getRegInfo()), Observer(Observer), KB(KB),
61 MDT(MDT), IsPreLegalize(IsPreLegalize), LI(LI),
62 RBI(Builder.getMF().getSubtarget().getRegBankInfo()),
63 TRI(Builder.getMF().getSubtarget().getRegisterInfo()) {
76 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
95 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
96 return ByteWidth -
I - 1;
116static std::optional<bool>
120 unsigned Width = MemOffset2Idx.
size();
123 bool BigEndian =
true, LittleEndian =
true;
124 for (
unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
125 auto MemOffsetAndIdx = MemOffset2Idx.
find(MemOffset);
126 if (MemOffsetAndIdx == MemOffset2Idx.
end())
128 const int64_t
Idx = MemOffsetAndIdx->second - LowestIdx;
129 assert(
Idx >= 0 &&
"Expected non-negative byte offset?");
132 if (!BigEndian && !LittleEndian)
136 assert((BigEndian != LittleEndian) &&
137 "Pattern cannot be both big and little endian!");
144 assert(
LI &&
"Must have LegalizerInfo to query isLegal!");
160 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
161 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
188 unsigned ToOpcode)
const {
213 if (
MI.getOpcode() != TargetOpcode::COPY)
222 MI.eraseFromParent();
244 if (OrigDef->
isPHI() || isa<GUnmerge>(OrigDef))
251 std::optional<MachineOperand> MaybePoisonOperand;
253 if (!Operand.isReg())
259 if (!MaybePoisonOperand)
260 MaybePoisonOperand = Operand;
269 if (!MaybePoisonOperand) {
272 cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
274 B.buildCopy(
DstOp, OrigOp);
279 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
280 LLT MaybePoisonOperandRegTy =
MRI.
getType(MaybePoisonOperandReg);
284 cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
287 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
298 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
299 "Invalid instruction");
309 assert(Def &&
"Operand not defined");
312 switch (Def->getOpcode()) {
313 case TargetOpcode::G_BUILD_VECTOR:
320 case TargetOpcode::G_IMPLICIT_DEF: {
329 "All undefs should have the same type");
333 EltIdx != EltEnd; ++EltIdx)
334 Ops.
push_back(Undef->getOperand(0).getReg());
345 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.
getType(Ops[0])}})) {
372 MI.eraseFromParent();
383 if (!ConcatMI1 || !ConcatMI2)
387 if (
MRI.
getType(ConcatMI1->getSourceReg(0)) !=
394 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
398 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
399 if (i + j >= Mask.size())
401 if (Mask[i + j] != -1)
405 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
408 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
409 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
410 if (i + j >= Mask.size())
412 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
418 Ops.
push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
420 Ops.
push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
421 ConcatMI1->getNumSources()));
429 {TargetOpcode::G_CONCAT_VECTORS,
430 {
MRI.
getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
441 for (
unsigned i = 0; i < Ops.
size(); i++) {
450 MI.eraseFromParent();
464 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
465 "Invalid instruction kind");
490 if (DstNumElts < 2 * SrcNumElts && DstNumElts != 1)
495 if (DstNumElts % SrcNumElts != 0)
501 unsigned NumConcat = DstNumElts / SrcNumElts;
504 for (
unsigned i = 0; i != DstNumElts; ++i) {
511 if ((
Idx % SrcNumElts != (i % SrcNumElts)) ||
512 (ConcatSrcs[i / SrcNumElts] >= 0 &&
513 ConcatSrcs[i / SrcNumElts] != (
int)(
Idx / SrcNumElts)))
516 ConcatSrcs[i / SrcNumElts] =
Idx / SrcNumElts;
523 for (
auto Src : ConcatSrcs) {
549 MI.eraseFromParent();
554 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
555 "Invalid instruction kind");
558 return Mask.size() == 1;
565 int I =
MI.getOperand(3).getShuffleMask()[0];
570 if (
I >= Src1NumElts) {
571 SrcReg =
MI.getOperand(2).getReg();
583 MI.eraseFromParent();
592 const LLT TyForCandidate,
593 unsigned OpcodeForCandidate,
598 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
609 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
612 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
613 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
614 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
620 if (!isa<GZExtLoad>(LoadMI) && CurrentUse.
Ty == TyForCandidate) {
622 OpcodeForCandidate == TargetOpcode::G_ZEXT)
624 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
625 OpcodeForCandidate == TargetOpcode::G_SEXT)
626 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
635 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
646static void InsertInsnsWithoutSideEffectsBeforeUse(
658 InsertBB = PredBB->
getMBB();
663 if (InsertBB ==
DefMI.getParent()) {
665 Inserter(InsertBB, std::next(InsertPt), UseMO);
684 unsigned CandidateLoadOpc;
686 case TargetOpcode::G_ANYEXT:
687 CandidateLoadOpc = TargetOpcode::G_LOAD;
689 case TargetOpcode::G_SEXT:
690 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
692 case TargetOpcode::G_ZEXT:
693 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
698 return CandidateLoadOpc;
729 if (!llvm::has_single_bit<uint32_t>(LoadValueTy.
getSizeInBits()))
737 unsigned PreferredOpcode =
739 ? TargetOpcode::G_ANYEXT
740 : isa<GSExtLoad>(&
MI) ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
741 Preferred = {
LLT(), PreferredOpcode,
nullptr};
743 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
744 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
745 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
746 const auto &MMO = LoadMI->
getMMO();
756 if (
LI->
getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
760 Preferred = ChoosePreferredUse(
MI, Preferred,
771 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
789 if (PreviouslyEmitted) {
799 EmittedInsns[InsertIntoBB] = NewMI;
811 Uses.push_back(&UseMO);
813 for (
auto *UseMO :
Uses) {
823 if (UseDstReg != ChosenDstReg) {
824 if (Preferred.
Ty == UseDstTy) {
861 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
876 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
879 MI.getOperand(0).setReg(ChosenDstReg);
885 assert(
MI.getOpcode() == TargetOpcode::G_AND);
904 APInt MaskVal = MaybeMask->Value;
925 if (MaskSizeBits > LoadSizeBits.
getValue())
945 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
951 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.
getType(PtrReg)}, {MemDesc}}))
955 B.setInstrAndDebugLoc(*LoadMI);
956 auto &MF =
B.getMF();
958 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
959 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
968 "shouldn't consider debug uses");
976 if (DefOrUse ==
MBB.
end())
978 return &*DefOrUse == &
DefMI;
984 "shouldn't consider debug uses");
987 else if (
DefMI.getParent() !=
UseMI.getParent())
994 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1003 LoadUser = TruncSrc;
1005 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1008 if (
auto *LoadMI = getOpcodeDef<GSExtLoad>(LoadUser,
MRI)) {
1010 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1014 if (LoadSizeBits == SizeInBits)
1021 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1023 MI.eraseFromParent();
1028 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1038 auto *LoadDef = getOpcodeDef<GLoad>(SrcReg,
MRI);
1042 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1047 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1050 if (NewSizeBits < 8)
1062 if (LoadDef->isSimple())
1064 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1074 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1080 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1082 unsigned ScalarSizeBits;
1083 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1092 auto &MMO = LoadDef->
getMMO();
1095 auto PtrInfo = MMO.getPointerInfo();
1099 MI.eraseFromParent();
1107 auto *MF =
MI->getMF();
1108 auto *
Addr = getOpcodeDef<GPtrAdd>(
MI->getPointerReg(),
MRI);
1114 AM.
BaseOffs = CstOff->getSExtValue();
1119 MF->getDataLayout(), AM,
1121 MF->getFunction().getContext()),
1122 MI->getMMO().getAddrSpace());
1127 case TargetOpcode::G_LOAD:
1128 return TargetOpcode::G_INDEXED_LOAD;
1129 case TargetOpcode::G_STORE:
1130 return TargetOpcode::G_INDEXED_STORE;
1131 case TargetOpcode::G_ZEXTLOAD:
1132 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1133 case TargetOpcode::G_SEXTLOAD:
1134 return TargetOpcode::G_INDEXED_SEXTLOAD;
1140bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1150 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1151 OpTys = {PtrTy, Ty, Ty};
1153 OpTys = {Ty, PtrTy};
1161 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1162 "considered for post-indexing."));
1166 bool &RematOffset) {
1179 if (!isIndexedLoadStoreLegal(LdSt))
1188 unsigned NumUsesChecked = 0;
1193 auto *PtrAdd = dyn_cast<GPtrAdd>(&
Use);
1201 if (StoredValDef == &
Use)
1204 Offset = PtrAdd->getOffsetReg();
1206 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1212 RematOffset =
false;
1216 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1222 if (&BasePtrUse == PtrDef)
1227 auto *BasePtrLdSt = dyn_cast<GLoadStore>(&BasePtrUse);
1228 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1230 isIndexedLoadStoreLegal(*BasePtrLdSt))
1235 if (
auto *BasePtrUseDef = dyn_cast<GPtrAdd>(&BasePtrUse)) {
1236 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1240 if (BaseUseUse.getParent() != LdSt.
getParent())
1243 if (
auto *UseUseLdSt = dyn_cast<GLoadStore>(&BaseUseUse))
1252 Addr = PtrAdd->getReg(0);
1253 Base = PtrAdd->getBaseReg();
1274 if (!isIndexedLoadStoreLegal(LdSt))
1278 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1281 if (
auto *St = dyn_cast<GStore>(&LdSt)) {
1283 if (
Base == St->getValueReg())
1288 if (St->getValueReg() ==
Addr)
1294 if (AddrUse.getParent() != LdSt.
getParent())
1299 bool RealUse =
false;
1306 if (
auto *UseLdSt = dyn_cast<GLoadStore>(&AddrUse)) {
1318 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1321 auto *LoadMI = getOpcodeDef<GLoad>(
MI.getOperand(1).getReg(),
MRI);
1335 if (!LoadMI->isSimple())
1347 const unsigned MaxIter = 20;
1350 if (
II->isLoadFoldBarrier())
1352 if (Iter++ == MaxIter)
1368 int Elt = CVal->getZExtValue();
1381 Register VecPtr = LoadMI->getPointerReg();
1389 LegalityQuery Q = {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}};
1414 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1424 auto &LdSt = cast<GLoadStore>(
MI);
1429 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1431 if (!MatchInfo.
IsPre &&
1432 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1442 unsigned Opcode =
MI.getOpcode();
1443 bool IsStore = Opcode == TargetOpcode::G_STORE;
1451 *OldCst->getOperand(1).getCImm());
1452 MatchInfo.
Offset = NewCst.getReg(0);
1458 MIB.
addUse(
MI.getOperand(0).getReg());
1460 MIB.
addDef(
MI.getOperand(0).getReg());
1468 MI.eraseFromParent();
1476 unsigned Opcode =
MI.getOpcode();
1477 bool IsDiv, IsSigned;
1482 case TargetOpcode::G_SDIV:
1483 case TargetOpcode::G_UDIV: {
1485 IsSigned = Opcode == TargetOpcode::G_SDIV;
1488 case TargetOpcode::G_SREM:
1489 case TargetOpcode::G_UREM: {
1491 IsSigned = Opcode == TargetOpcode::G_SREM;
1497 unsigned DivOpcode, RemOpcode, DivremOpcode;
1499 DivOpcode = TargetOpcode::G_SDIV;
1500 RemOpcode = TargetOpcode::G_SREM;
1501 DivremOpcode = TargetOpcode::G_SDIVREM;
1503 DivOpcode = TargetOpcode::G_UDIV;
1504 RemOpcode = TargetOpcode::G_UREM;
1505 DivremOpcode = TargetOpcode::G_UDIVREM;
1524 if (
MI.getParent() ==
UseMI.getParent() &&
1525 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1526 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1539 unsigned Opcode =
MI.getOpcode();
1540 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1543 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1544 DestDivReg =
MI.getOperand(0).getReg();
1548 DestRemReg =
MI.getOperand(0).getReg();
1552 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1562 : TargetOpcode::G_UDIVREM,
1563 {DestDivReg, DestRemReg},
1565 MI.eraseFromParent();
1571 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1590 assert(std::next(BrIt) ==
MBB->
end() &&
"expected G_BR to be a terminator");
1592 BrCond = &*std::prev(BrIt);
1593 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1599 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1617 MI.getOperand(0).setMBB(FallthroughBB);
1633 return Helper.lowerMemcpyInline(
MI) ==
1649 switch (
MI.getOpcode()) {
1652 case TargetOpcode::G_FNEG: {
1653 Result.changeSign();
1656 case TargetOpcode::G_FABS: {
1660 case TargetOpcode::G_FPTRUNC: {
1662 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1667 case TargetOpcode::G_FSQRT: {
1671 Result =
APFloat(sqrt(Result.convertToDouble()));
1674 case TargetOpcode::G_FLOG2: {
1695 MI.eraseFromParent();
1706 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1716 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1729 Type *AccessTy =
nullptr;
1730 auto &MF = *
MI.getMF();
1732 if (
auto *LdSt = dyn_cast<GLoadStore>(&
UseMI)) {
1734 MF.getFunction().getContext());
1739 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1744 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1747 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1748 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1749 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1762 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1768 MI.getOperand(1).setReg(MatchInfo.
Base);
1769 MI.getOperand(2).setReg(NewOffset.getReg(0));
1782 unsigned Opcode =
MI.getOpcode();
1783 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1784 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1785 Opcode == TargetOpcode::G_USHLSAT) &&
1786 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1806 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1811 if (Opcode == TargetOpcode::G_USHLSAT &&
1820 unsigned Opcode =
MI.getOpcode();
1821 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1822 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1823 Opcode == TargetOpcode::G_USHLSAT) &&
1824 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1828 auto Imm = MatchInfo.
Imm;
1830 if (Imm >= ScalarSizeInBits) {
1832 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1834 MI.eraseFromParent();
1839 Imm = ScalarSizeInBits - 1;
1845 MI.getOperand(1).setReg(MatchInfo.
Reg);
1846 MI.getOperand(2).setReg(NewImm);
1862 unsigned ShiftOpcode =
MI.getOpcode();
1863 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1864 ShiftOpcode == TargetOpcode::G_ASHR ||
1865 ShiftOpcode == TargetOpcode::G_LSHR ||
1866 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1867 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1868 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1871 Register LogicDest =
MI.getOperand(1).getReg();
1876 unsigned LogicOpcode = LogicMI->
getOpcode();
1877 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1878 LogicOpcode != TargetOpcode::G_XOR)
1882 const Register C1 =
MI.getOperand(2).getReg();
1884 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1887 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1891 if (
MI->getOpcode() != ShiftOpcode ||
1901 ShiftVal = MaybeImmVal->Value.getSExtValue();
1912 if (matchFirstShift(LogicMIOp1, C0Val)) {
1914 MatchInfo.
Shift2 = LogicMIOp1;
1915 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
1917 MatchInfo.
Shift2 = LogicMIOp2;
1921 MatchInfo.
ValSum = C0Val + C1Val;
1927 MatchInfo.
Logic = LogicMI;
1933 unsigned Opcode =
MI.getOpcode();
1934 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1935 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
1936 Opcode == TargetOpcode::G_SSHLSAT) &&
1937 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1955 Register Shift2Const =
MI.getOperand(2).getReg();
1967 MI.eraseFromParent();
1971 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
1974 auto &Shl = cast<GenericMachineInstr>(
MI);
1994 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
1995 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
1998 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
1999 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2000 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {
S1, S2});
2006 unsigned &ShiftVal) {
2007 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2013 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2014 return (
static_cast<int32_t
>(ShiftVal) != -1);
2018 unsigned &ShiftVal) {
2019 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2024 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2025 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2032 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
KB);
2047 if (!MaybeShiftAmtVal)
2061 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2062 MatchData.
Reg = ExtSrc;
2063 MatchData.
Imm = ShiftAmt;
2067 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2073 int64_t ShiftAmtVal = MatchData.
Imm;
2080 MI.eraseFromParent();
2087 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2090 auto *Unmerge = getOpcodeDef<GUnmerge>(MergedValues[0],
MRI);
2091 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2094 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2095 if (MergedValues[
I] != Unmerge->getReg(
I))
2098 MatchInfo = Unmerge->getSourceReg();
2112 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2113 "Expected an unmerge");
2114 auto &Unmerge = cast<GUnmerge>(
MI);
2117 auto *SrcInstr = getOpcodeDef<GMergeLikeInstr>(SrcReg,
MRI);
2125 if (SrcMergeTy != Dst0Ty && !SameSize)
2129 for (
unsigned Idx = 0;
Idx < SrcInstr->getNumSources(); ++
Idx)
2136 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2137 "Expected an unmerge");
2139 "Not enough operands to replace all defs");
2140 unsigned NumElems =
MI.getNumOperands() - 1;
2144 bool CanReuseInputDirectly = DstTy == SrcTy;
2145 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2157 if (CanReuseInputDirectly)
2162 MI.eraseFromParent();
2167 unsigned SrcIdx =
MI.getNumOperands() - 1;
2168 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2170 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2171 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2182 for (
unsigned Idx = 0;
Idx != SrcIdx; ++
Idx) {
2184 Val = Val.
lshr(ShiftAmt);
2192 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2193 "Expected an unmerge");
2195 "Not enough operands to replace all defs");
2196 unsigned NumElems =
MI.getNumOperands() - 1;
2197 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2202 MI.eraseFromParent();
2207 unsigned SrcIdx =
MI.getNumOperands() - 1;
2208 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2210 unsigned NumElems =
MI.getNumOperands() - 1;
2211 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2213 B.buildUndef(DstReg);
2220 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2221 "Expected an unmerge");
2226 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs();
Idx != EndIdx; ++
Idx) {
2234 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2235 Register Dst0Reg =
MI.getOperand(0).getReg();
2237 MI.eraseFromParent();
2241 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2242 "Expected an unmerge");
2243 Register Dst0Reg =
MI.getOperand(0).getReg();
2250 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2267 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2268 "Expected an unmerge");
2270 Register Dst0Reg =
MI.getOperand(0).getReg();
2275 "Expecting a G_ZEXT");
2285 "ZExt src doesn't fit in destination");
2290 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs();
Idx != EndIdx; ++
Idx) {
2295 MI.eraseFromParent();
2299 unsigned TargetShiftSize,
2300 unsigned &ShiftVal) {
2301 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2302 MI.getOpcode() == TargetOpcode::G_LSHR ||
2303 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2311 if (
Size <= TargetShiftSize)
2319 ShiftVal = MaybeImmVal->Value.getSExtValue();
2320 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2324 const unsigned &ShiftVal) {
2329 unsigned HalfSize =
Size / 2;
2330 assert(ShiftVal >= HalfSize);
2335 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2337 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2338 Register Narrowed = Unmerge.getReg(1);
2345 if (NarrowShiftAmt != 0) {
2352 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2353 Register Narrowed = Unmerge.getReg(0);
2358 if (NarrowShiftAmt != 0) {
2366 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2368 HalfTy, Unmerge.getReg(1),
2371 if (ShiftVal == HalfSize) {
2375 }
else if (ShiftVal ==
Size - 1) {
2383 HalfTy, Unmerge.getReg(1),
2392 MI.eraseFromParent();
2396 unsigned TargetShiftAmount) {
2407 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2416 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2419 MI.eraseFromParent();
2423 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2426 MI.eraseFromParent();
2431 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2438 PtrReg.second =
false;
2448 PtrReg.second =
true;
2460 const bool DoCommute = PtrReg.second;
2469 MI.eraseFromParent();
2474 auto &PtrAdd = cast<GPtrAdd>(
MI);
2485 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2495 auto &PtrAdd = cast<GPtrAdd>(
MI);
2499 PtrAdd.eraseFromParent();
2503 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2508 SrcReg = OriginalSrcReg;
2515 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2530 assert((
MI.getOpcode() == TargetOpcode::G_ANYEXT ||
2531 MI.getOpcode() == TargetOpcode::G_SEXT ||
2532 MI.getOpcode() == TargetOpcode::G_ZEXT) &&
2533 "Expected a G_[ASZ]EXT");
2537 SrcReg = OriginalSrcReg;
2540 unsigned Opc =
MI.getOpcode();
2542 if (Opc == SrcOpc ||
2543 (Opc == TargetOpcode::G_ANYEXT &&
2544 (SrcOpc == TargetOpcode::G_SEXT || SrcOpc == TargetOpcode::G_ZEXT)) ||
2545 (Opc == TargetOpcode::G_SEXT && SrcOpc == TargetOpcode::G_ZEXT)) {
2554 assert((
MI.getOpcode() == TargetOpcode::G_ANYEXT ||
2555 MI.getOpcode() == TargetOpcode::G_SEXT ||
2556 MI.getOpcode() == TargetOpcode::G_ZEXT) &&
2557 "Expected a G_[ASZ]EXT");
2559 Register Reg = std::get<0>(MatchInfo);
2560 unsigned SrcExtOp = std::get<1>(MatchInfo);
2563 if (
MI.getOpcode() == SrcExtOp) {
2565 MI.getOperand(1).setReg(Reg);
2573 if (
MI.getOpcode() == TargetOpcode::G_ANYEXT ||
2574 (
MI.getOpcode() == TargetOpcode::G_SEXT &&
2575 SrcExtOp == TargetOpcode::G_ZEXT)) {
2578 MI.eraseFromParent();
2584 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2588 if (SrcOpc == TargetOpcode::G_ANYEXT || SrcOpc == TargetOpcode::G_SEXT ||
2589 SrcOpc == TargetOpcode::G_ZEXT) {
2598 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2600 unsigned SrcExtOp = MatchInfo.second;
2604 if (SrcTy == DstTy) {
2605 MI.eraseFromParent();
2613 MI.eraseFromParent();
2621 if (ShiftSize > 32 && TruncSize < 32)
2635 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2652 case TargetOpcode::G_SHL: {
2661 case TargetOpcode::G_LSHR:
2662 case TargetOpcode::G_ASHR: {
2669 if (
User.getOpcode() == TargetOpcode::G_STORE)
2673 if (NewShiftTy == SrcTy)
2687 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2690 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2697 LLT NewShiftTy = MatchInfo.second;
2711 if (NewShiftTy == DstTy)
2721 return MO.isReg() &&
2722 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2728 return !MO.isReg() ||
2729 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2734 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2736 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2740 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2741 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2746 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2747 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2752 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2753 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2754 "Expected an insert/extract element op");
2757 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2770 OpIdx = Cst->isZero() ? 3 : 2;
2815 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2842 return MO.isReg() && MO.getReg().isPhysical();
2852 return I1->isIdenticalTo(*I2);
2867 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2878 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2879 MaybeCst->getSExtValue() ==
C;
2885 std::optional<FPValueAndVReg> MaybeCst;
2889 return MaybeCst->Value.isExactlyValue(
C);
2894 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2896 Register Replacement =
MI.getOperand(OpIdx).getReg();
2898 MI.eraseFromParent();
2904 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2907 MI.eraseFromParent();
2912 unsigned ConstIdx) {
2913 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
2926 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
2927 MI.getOpcode() == TargetOpcode::G_FSHR) &&
2928 "This is not a funnel shift operation");
2930 Register ConstReg =
MI.getOperand(3).getReg();
2935 assert((VRegAndVal) &&
"Value is not a constant");
2938 APInt NewConst = VRegAndVal->Value.
urem(
2943 MI.getOpcode(), {MI.getOperand(0)},
2944 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
2946 MI.eraseFromParent();
2950 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2971 return MO.
isReg() &&
2982 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2984 MI.eraseFromParent();
2988 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2990 MI.eraseFromParent();
2994 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2996 MI.eraseFromParent();
3001 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3003 MI.eraseFromParent();
3007 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3009 MI.eraseFromParent();
3016 Register &NewLHS = std::get<0>(MatchInfo);
3017 Register &NewRHS = std::get<1>(MatchInfo);
3025 NewLHS = MaybeNewLHS;
3034 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3043 TargetOpcode::G_INSERT_VECTOR_ELT)
3049 MatchInfo.
resize(NumElts);
3053 if (IntImm >= NumElts || IntImm < 0)
3055 if (!MatchInfo[IntImm])
3056 MatchInfo[IntImm] = TmpReg;
3060 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3062 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3071 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3078 auto GetUndef = [&]() {
3090 MI.eraseFromParent();
3096 std::tie(SubLHS, SubRHS) = MatchInfo;
3098 MI.eraseFromParent();
3109 unsigned LogicOpcode =
MI.getOpcode();
3110 assert(LogicOpcode == TargetOpcode::G_AND ||
3111 LogicOpcode == TargetOpcode::G_OR ||
3112 LogicOpcode == TargetOpcode::G_XOR);
3125 if (!LeftHandInst || !RightHandInst)
3127 unsigned HandOpcode = LeftHandInst->
getOpcode();
3128 if (HandOpcode != RightHandInst->
getOpcode())
3140 if (!XTy.
isValid() || XTy != YTy)
3145 switch (HandOpcode) {
3148 case TargetOpcode::G_ANYEXT:
3149 case TargetOpcode::G_SEXT:
3150 case TargetOpcode::G_ZEXT: {
3154 case TargetOpcode::G_TRUNC: {
3170 case TargetOpcode::G_AND:
3171 case TargetOpcode::G_ASHR:
3172 case TargetOpcode::G_LSHR:
3173 case TargetOpcode::G_SHL: {
3178 ExtraHandOpSrcReg = ZOp.
getReg();
3200 if (ExtraHandOpSrcReg.
isValid())
3212 "Expected at least one instr to build?");
3214 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3215 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3217 for (
auto &OperandFn : InstrToBuild.OperandFns)
3220 MI.eraseFromParent();
3225 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3226 int64_t ShlCst, AshrCst;
3232 if (ShlCst != AshrCst)
3235 {TargetOpcode::G_SEXT_INREG, {
MRI.
getType(Src)}}))
3237 MatchInfo = std::make_tuple(Src, ShlCst);
3243 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3246 std::tie(Src, ShiftAmt) = MatchInfo;
3249 MI.eraseFromParent();
3255 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3270 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3273 auto Zero =
B.buildConstant(Ty, 0);
3296 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3320 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3327 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3343 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3361 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3368 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3379 unsigned ExtBits =
MI.getOperand(2).getImm();
3385 int64_t Cst,
bool IsVector,
bool IsFP) {
3387 return (ScalarSizeBits == 1 && Cst == -1) ||
3393 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3413 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3418 switch (Def->getOpcode()) {
3423 case TargetOpcode::G_ICMP:
3429 case TargetOpcode::G_FCMP:
3435 case TargetOpcode::G_AND:
3436 case TargetOpcode::G_OR:
3442 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3443 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3470 for (
Register Reg : RegsToNegate) {
3475 switch (Def->getOpcode()) {
3478 case TargetOpcode::G_ICMP:
3479 case TargetOpcode::G_FCMP: {
3486 case TargetOpcode::G_AND:
3489 case TargetOpcode::G_OR:
3497 MI.eraseFromParent();
3503 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3507 Register SharedReg =
MI.getOperand(2).getReg();
3528 return Y == SharedReg;
3535 std::tie(
X,
Y) = MatchInfo;
3539 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3540 MI.getOperand(2).setReg(
Y);
3545 auto &PtrAdd = cast<GPtrAdd>(
MI);
3546 Register DstReg = PtrAdd.getReg(0);
3555 return ConstVal && *ConstVal == 0;
3564 auto &PtrAdd = cast<GPtrAdd>(
MI);
3566 PtrAdd.eraseFromParent();
3573 Register Pow2Src1 =
MI.getOperand(2).getReg();
3580 MI.eraseFromParent();
3584 unsigned &SelectOpNo) {
3594 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3596 OtherOperandReg =
LHS;
3599 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3616 unsigned BinOpcode =
MI.getOpcode();
3621 bool CanFoldNonConst =
3622 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3627 if (CanFoldNonConst)
3638 const unsigned &SelectOperand) {
3649 unsigned BinOpcode =
MI.getOpcode();
3656 if (SelectOperand == 1) {
3670 MI.eraseFromParent();
3673std::optional<SmallVector<Register, 8>>
3674CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3675 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3704 const unsigned MaxIter =
3706 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3715 return std::nullopt;
3731 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
3732 return std::nullopt;
3744static std::optional<std::pair<GZExtLoad *, int64_t>>
3748 "Expected Reg to only have one non-debug use?");
3757 if (Shift % MemSizeInBits != 0)
3758 return std::nullopt;
3761 auto *Load = getOpcodeDef<GZExtLoad>(MaybeLoad,
MRI);
3763 return std::nullopt;
3765 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
3766 return std::nullopt;
3768 return std::make_pair(Load, Shift / MemSizeInBits);
3771std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
3772CombinerHelper::findLoadOffsetsForLoadOrCombine(
3806 for (
auto Reg : RegsToVisit) {
3811 return std::nullopt;
3814 std::tie(Load, DstPos) = *LoadAndPos;
3822 return std::nullopt;
3825 auto &LoadMMO =
Load->getMMO();
3829 return std::nullopt;
3836 LoadPtr =
Load->getOperand(1).getReg();
3842 return std::nullopt;
3849 if (BasePtr != LoadPtr)
3850 return std::nullopt;
3852 if (
Idx < LowestIdx) {
3854 LowestIdxLoad =
Load;
3862 return std::nullopt;
3870 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
3871 EarliestLoad =
Load;
3872 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
3879 "Expected to find a load for each register?");
3880 assert(EarliestLoad != LatestLoad && EarliestLoad &&
3881 LatestLoad &&
"Expected at least two loads?");
3890 const unsigned MaxIter = 20;
3896 if (
MI.isLoadFoldBarrier())
3897 return std::nullopt;
3898 if (Iter++ == MaxIter)
3899 return std::nullopt;
3902 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
3907 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3927 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
3931 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
3938 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
3939 if (NarrowMemSizeInBits % 8 != 0)
3952 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
3953 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
3956 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
3963 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
3966 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
3978 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
3979 const unsigned ZeroByteOffset =
3983 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
3984 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
3985 ZeroOffsetIdx->second != LowestIdx)
4009 MIB.setInstrAndDebugLoc(*LatestLoad);
4011 MIB.buildLoad(LoadDst,
Ptr, *NewMMO);
4013 MIB.buildBSwap(Dst, LoadDst);
4020 auto &
PHI = cast<GPhi>(
MI);
4033 case TargetOpcode::G_ANYEXT:
4035 case TargetOpcode::G_ZEXT:
4036 case TargetOpcode::G_SEXT:
4050 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4053 case TargetOpcode::G_LOAD:
4054 case TargetOpcode::G_TRUNC:
4055 case TargetOpcode::G_SEXT:
4056 case TargetOpcode::G_ZEXT:
4057 case TargetOpcode::G_ANYEXT:
4058 case TargetOpcode::G_CONSTANT:
4062 if (InSrcs.
size() > 2)
4074 auto &
PHI = cast<GPhi>(
MI);
4083 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4084 auto SrcReg =
PHI.getIncomingValue(
I);
4086 if (!SrcMIs.
insert(SrcMI))
4092 if (InsertPt !=
MBB->
end() && InsertPt->isPHI())
4098 OldToNewSrcMap[SrcMI] = NewExt;
4107 NewPhi.
addMBB(MO.getMBB());
4111 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4119 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4129 unsigned VecIdx = Cst->Value.getZExtValue();
4134 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4138 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4139 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4159 if (ScalarTy != DstTy) {
4162 MI.eraseFromParent();
4171 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4194 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4199 unsigned Idx = Cst->getZExtValue();
4203 SrcDstPairs.emplace_back(
4204 std::make_pair(
MI.getOperand(
Idx + 1).getReg(), &
II));
4207 return ExtractedElts.
all();
4213 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4214 for (
auto &Pair : SrcDstPairs) {
4215 auto *ExtMI = Pair.second;
4217 ExtMI->eraseFromParent();
4219 MI.eraseFromParent();
4225 MI.eraseFromParent();
4235 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4241 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4242 unsigned FshOpc = 0;
4253 int64_t CstShlAmt, CstLShrAmt;
4256 CstShlAmt + CstLShrAmt ==
BitWidth) {
4257 FshOpc = TargetOpcode::G_FSHR;
4264 FshOpc = TargetOpcode::G_FSHL;
4270 FshOpc = TargetOpcode::G_FSHR;
4281 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4288 unsigned Opc =
MI.getOpcode();
4289 assert(Opc == TargetOpcode::G_FSHL || Opc == TargetOpcode::G_FSHR);
4294 unsigned RotateOpc =
4295 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4300 unsigned Opc =
MI.getOpcode();
4301 assert(Opc == TargetOpcode::G_FSHL || Opc == TargetOpcode::G_FSHR);
4302 bool IsFSHL = Opc == TargetOpcode::G_FSHL;
4305 : TargetOpcode::G_ROTR));
4306 MI.removeOperand(2);
4312 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4313 MI.getOpcode() == TargetOpcode::G_ROTR);
4317 bool OutOfRange =
false;
4318 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4319 if (
auto *CI = dyn_cast<ConstantInt>(
C))
4320 OutOfRange |= CI->getValue().uge(Bitsize);
4327 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4328 MI.getOpcode() == TargetOpcode::G_ROTR);
4336 MI.getOperand(2).setReg(Amt);
4341 int64_t &MatchInfo) {
4342 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4354 if (KnownRHS.isUnknown())
4357 std::optional<bool> KnownVal;
4358 if (KnownRHS.isZero()) {
4419 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4444 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4450 unsigned Op = TargetOpcode::COPY;
4451 if (DstSize != LHSSize)
4452 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4462 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4472 int64_t AndMaskBits;
4480 if (AndMaskBits & OrMaskBits)
4486 if (
MI.getOperand(1).getReg() == AndMaskReg)
4487 MI.getOperand(2).setReg(AndMaskReg);
4488 MI.getOperand(1).setReg(Src);
4497 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4504 int64_t Width =
MI.getOperand(2).getImm();
4516 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4517 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4518 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4526 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4533 int64_t AndImm, LSBImm;
4542 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4543 if (MaybeMask & (MaybeMask + 1))
4552 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4553 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4554 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4561 const unsigned Opcode =
MI.getOpcode();
4562 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4564 const Register Dst =
MI.getOperand(0).getReg();
4566 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4567 ? TargetOpcode::G_SBFX
4568 : TargetOpcode::G_UBFX;
4589 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4593 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4597 const int64_t Pos = ShrAmt - ShlAmt;
4598 const int64_t Width =
Size - ShrAmt;
4601 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4602 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4603 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4610 const unsigned Opcode =
MI.getOpcode();
4611 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4613 const Register Dst =
MI.getOperand(0).getReg();
4630 if (ShrAmt < 0 || ShrAmt >=
Size)
4634 if (0 == (SMask >> ShrAmt)) {
4636 B.buildConstant(Dst, 0);
4643 UMask |= maskTrailingOnes<uint64_t>(ShrAmt);
4644 UMask &= maskTrailingOnes<uint64_t>(
Size);
4649 const int64_t Pos = ShrAmt;
4654 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4658 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4659 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4660 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4665bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4667 auto &PtrAdd = cast<GPtrAdd>(
MI);
4669 Register Src1Reg = PtrAdd.getBaseReg();
4670 auto *Src1Def = getOpcodeDef<GPtrAdd>(Src1Reg,
MRI);
4674 Register Src2Reg = PtrAdd.getOffsetReg();
4686 const APInt &C1APIntVal = *C1;
4687 const APInt &C2APIntVal = *C2;
4688 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4694 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4695 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4696 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4703 auto *LdStMI = dyn_cast<GLoadStore>(ConvUseMI);
4714 PtrAdd.getMF()->getFunction().getContext());
4715 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4716 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4722 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4734 Register Src1Reg =
MI.getOperand(1).getReg();
4735 if (
RHS->getOpcode() != TargetOpcode::G_ADD)
4747 MI.getOperand(1).setReg(NewBase.getReg(0));
4748 MI.getOperand(2).setReg(
RHS->getOperand(2).getReg());
4751 return !reassociationCanBreakAddressingModePattern(
MI);
4761 std::optional<ValueAndVReg> LHSCstOff;
4766 auto *LHSPtrAdd = cast<GPtrAdd>(
LHS);
4771 LHSPtrAdd->moveBefore(&
MI);
4774 auto NewCst =
B.buildConstant(
MRI.
getType(RHSReg), LHSCstOff->Value);
4776 MI.getOperand(2).setReg(NewCst.getReg(0));
4779 LHSPtrAdd->getOperand(2).setReg(RHSReg);
4782 return !reassociationCanBreakAddressingModePattern(
MI);
4790 auto *LHSPtrAdd = dyn_cast<GPtrAdd>(
LHS);
4794 Register Src2Reg =
MI.getOperand(2).getReg();
4795 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
4796 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
4805 auto NewCst =
B.buildConstant(
MRI.
getType(Src2Reg), *C1 + *C2);
4807 MI.getOperand(1).setReg(LHSSrc1);
4808 MI.getOperand(2).setReg(NewCst.getReg(0));
4811 return !reassociationCanBreakAddressingModePattern(
MI);
4816 auto &PtrAdd = cast<GPtrAdd>(
MI);
4868 auto NewCst =
B.buildInstr(Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
4869 B.buildInstr(Opc, {DstReg}, {OpLHSLHS, NewCst});
4877 auto NewLHSLHS =
B.buildInstr(Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
4878 B.buildInstr(Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
4891 unsigned Opc =
MI.getOpcode();
4908 MatchInfo = *MaybeCst;
4921 MatchInfo = *MaybeCst;
4932 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
4938 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
4939 MI.getOpcode() == TargetOpcode::G_FMAD);
4940 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
4957 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
4979 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5003 case TargetOpcode::G_ADD:
5004 case TargetOpcode::G_SUB:
5005 case TargetOpcode::G_MUL:
5006 case TargetOpcode::G_AND:
5007 case TargetOpcode::G_OR:
5008 case TargetOpcode::G_XOR:
5016 auto Mask = Cst->Value;
5021 unsigned NarrowWidth = Mask.countr_one();
5027 auto &MF = *
MI.getMF();
5030 auto &
DL = MF.getDataLayout();
5031 if (!TLI.isTruncateFree(WideTy, NarrowTy,
DL, Ctx) ||
5032 !TLI.isZExtFree(NarrowTy, WideTy,
DL, Ctx))
5046 MI.getOperand(1).setReg(Ext.getReg(0));
5053 unsigned Opc =
MI.getOpcode();
5054 assert(Opc == TargetOpcode::G_UMULO || Opc == TargetOpcode::G_SMULO);
5061 unsigned NewOpc = Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5062 : TargetOpcode::G_SADDO;
5064 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5072 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5073 MI.getOpcode() == TargetOpcode::G_SMULO);
5082 B.buildConstant(Dst, 0);
5083 B.buildConstant(Carry, 0);
5091 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5092 MI.getOpcode() == TargetOpcode::G_SADDE ||
5093 MI.getOpcode() == TargetOpcode::G_USUBE ||
5094 MI.getOpcode() == TargetOpcode::G_SSUBE);
5099 switch (
MI.getOpcode()) {
5100 case TargetOpcode::G_UADDE:
5101 NewOpcode = TargetOpcode::G_UADDO;
5103 case TargetOpcode::G_SADDE:
5104 NewOpcode = TargetOpcode::G_SADDO;
5106 case TargetOpcode::G_USUBE:
5107 NewOpcode = TargetOpcode::G_USUBO;
5109 case TargetOpcode::G_SSUBE:
5110 NewOpcode = TargetOpcode::G_SSUBO;
5114 MI.setDesc(
B.getTII().get(NewOpcode));
5115 MI.removeOperand(4);
5123 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5157 B.buildSub(Dst, Zero, ReplaceReg);
5166 assert(
MI.getOpcode() == TargetOpcode::G_UDIV);
5167 auto &UDiv = cast<GenericMachineInstr>(
MI);
5177 unsigned KnownLeadingZeros =
5181 bool UseNPQ =
false;
5184 auto BuildUDIVPattern = [&](
const Constant *
C) {
5185 auto *CI = cast<ConstantInt>(
C);
5186 const APInt &Divisor = CI->getValue();
5188 bool SelNPQ =
false;
5190 unsigned PreShift = 0, PostShift = 0;
5195 if (!Divisor.
isOne()) {
5201 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5203 Magic = std::move(magics.
Magic);
5206 "We shouldn't generate an undefined shift!");
5208 "We shouldn't generate an undefined shift!");
5212 SelNPQ = magics.
IsAdd;
5216 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5217 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5219 MIB.buildConstant(ScalarTy,
5224 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5232 assert(Matched &&
"Expected unary predicate match to succeed");
5234 Register PreShift, PostShift, MagicFactor, NPQFactor;
5235 auto *RHSDef = getOpcodeDef<GBuildVector>(
RHS,
MRI);
5237 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5238 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5239 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5240 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5243 "Non-build_vector operation should have been a scalar");
5244 PreShift = PreShifts[0];
5245 MagicFactor = MagicFactors[0];
5246 PostShift = PostShifts[0];
5250 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5253 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5256 Register NPQ = MIB.buildSub(Ty,
LHS, Q).getReg(0);
5261 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5263 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5265 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5268 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5269 auto One = MIB.buildConstant(Ty, 1);
5270 auto IsOne = MIB.buildICmp(
5273 return MIB.buildSelect(Ty, IsOne,
LHS, Q);
5277 assert(
MI.getOpcode() == TargetOpcode::G_UDIV);
5285 auto &MF = *
MI.getMF();
5289 auto &
DL = MF.getDataLayout();
5295 if (MF.getFunction().hasMinSize())
5305 {TargetOpcode::G_ICMP,
5321 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5326 auto &MF = *
MI.getMF();
5330 auto &
DL = MF.getDataLayout();
5336 if (MF.getFunction().hasMinSize())
5355 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5356 auto &SDiv = cast<GenericMachineInstr>(
MI);
5366 bool UseSRA =
false;
5372 auto BuildSDIVPattern = [&](
const Constant *
C) {
5374 if (IsSplat && !Factors.
empty()) {
5380 auto *CI = cast<ConstantInt>(
C);
5381 APInt Divisor = CI->getValue();
5391 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5392 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5399 assert(Matched &&
"Expected unary predicate match to succeed");
5403 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5404 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5407 Factor = Factors[0];
5415 return MIB.buildMul(Ty, Res, Factor);
5419 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5420 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5421 "Expected SDIV or UDIV");
5422 auto &Div = cast<GenericMachineInstr>(
MI);
5424 auto MatchPow2 = [&](
const Constant *
C) {
5425 auto *CI = dyn_cast<ConstantInt>(
C);
5426 return CI && (CI->getValue().isPowerOf2() ||
5427 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5433 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5434 auto &SDiv = cast<GenericMachineInstr>(
MI);
5488 MI.eraseFromParent();
5492 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5493 auto &UDiv = cast<GenericMachineInstr>(
MI);
5502 MI.eraseFromParent();
5506 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
5511 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
5512 if (
auto *CI = dyn_cast<ConstantInt>(
C))
5513 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
5534 MI.eraseFromParent();
5539 unsigned Opc =
MI.getOpcode();
5540 assert(Opc == TargetOpcode::G_FADD || Opc == TargetOpcode::G_FSUB ||
5541 Opc == TargetOpcode::G_FMUL || Opc == TargetOpcode::G_FDIV ||
5542 Opc == TargetOpcode::G_FMAD || Opc == TargetOpcode::G_FMA);
5554 Opc = TargetOpcode::G_FSUB;
5559 Opc = TargetOpcode::G_FADD;
5565 else if ((Opc == TargetOpcode::G_FMUL || Opc == TargetOpcode::G_FDIV ||
5566 Opc == TargetOpcode::G_FMAD || Opc == TargetOpcode::G_FMA) &&
5575 MI.setDesc(
B.getTII().get(Opc));
5576 MI.getOperand(1).setReg(
X);
5577 MI.getOperand(2).setReg(
Y);
5584 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
5587 MatchInfo =
MI.getOperand(2).getReg();
5597 if (LHSCst->Value.isNegZero())
5601 if (LHSCst->Value.isPosZero())
5617 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
5625 MRI.use_instr_nodbg_end()) >
5627 MRI.use_instr_nodbg_end());
5631 bool &AllowFusionGlobally,
5633 bool CanReassociate) {
5635 auto *MF =
MI.getMF();
5636 const auto &TLI = *MF->getSubtarget().getTargetLowering();
5640 if (CanReassociate &&
5647 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
5650 if (!HasFMAD && !HasFMA)
5654 Options.UnsafeFPMath || HasFMAD;
5659 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
5665 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5667 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5675 unsigned PreferredFusedOpcode =
5676 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5690 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5691 {
LHS.MI->getOperand(1).getReg(),
5692 LHS.MI->getOperand(2).getReg(),
RHS.Reg});
5701 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5702 {
RHS.MI->getOperand(1).getReg(),
5703 RHS.MI->getOperand(2).getReg(),
LHS.Reg});
5713 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5715 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5719 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
5726 unsigned PreferredFusedOpcode =
5727 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5741 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5746 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5747 {FpExtX.getReg(0), FpExtY.getReg(0),
RHS.Reg});
5756 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5761 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5762 {FpExtX.getReg(0), FpExtY.getReg(0),
LHS.Reg});
5772 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5774 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5784 unsigned PreferredFusedOpcode =
5785 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5798 if (
LHS.MI->getOpcode() == PreferredFusedOpcode &&
5800 TargetOpcode::G_FMUL) &&
5807 else if (
RHS.MI->getOpcode() == PreferredFusedOpcode &&
5809 TargetOpcode::G_FMUL) &&
5818 Register X = FMA->getOperand(1).getReg();
5819 Register Y = FMA->getOperand(2).getReg();
5825 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
5826 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5837 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5839 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5846 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
5853 unsigned PreferredFusedOpcode =
5854 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5867 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
5868 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
5870 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
5872 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5879 if (
LHS.MI->getOpcode() == PreferredFusedOpcode &&
5883 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5888 LHS.MI->getOperand(1).getReg(),
5889 LHS.MI->getOperand(2).getReg(),
B);
5900 FMAMI->
getOpcode() == PreferredFusedOpcode) {
5903 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5908 X =
B.buildFPExt(DstType,
X).getReg(0);
5909 Y =
B.buildFPExt(DstType,
Y).getReg(0);
5920 if (
RHS.MI->getOpcode() == PreferredFusedOpcode &&
5924 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5929 RHS.MI->getOperand(1).getReg(),
5930 RHS.MI->getOperand(2).getReg(),
B);
5941 FMAMI->
getOpcode() == PreferredFusedOpcode) {
5944 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5949 X =
B.buildFPExt(DstType,
X).getReg(0);
5950 Y =
B.buildFPExt(DstType,
Y).getReg(0);
5963 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
5965 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5977 int FirstMulHasFewerUses =
true;
5981 FirstMulHasFewerUses =
false;
5983 unsigned PreferredFusedOpcode =
5984 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5987 if (FirstMulHasFewerUses &&
5992 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5993 {
LHS.MI->getOperand(1).getReg(),
5994 LHS.MI->getOperand(2).getReg(), NegZ});
6003 B.buildFNeg(DstTy,
RHS.MI->getOperand(1).getReg()).
getReg(0);
6004 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6005 {NegY,
RHS.MI->getOperand(2).getReg(),
LHS.Reg});
6015 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6017 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6025 unsigned PreferredFusedOpcode =
6026 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6037 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6038 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6050 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6062 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6064 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6072 unsigned PreferredFusedOpcode =
6073 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6085 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6086 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6087 {FpExtX, FpExtY, NegZ});
6099 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6102 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6103 {NegY, FpExtZ, LHSReg});
6113 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6115 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6119 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6124 unsigned PreferredFusedOpcode =
6125 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6129 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6130 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6131 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6142 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6148 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6158 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6171 unsigned &IdxToPropagate) {
6173 switch (
MI.getOpcode()) {
6176 case TargetOpcode::G_FMINNUM:
6177 case TargetOpcode::G_FMAXNUM:
6178 PropagateNaN =
false;
6180 case TargetOpcode::G_FMINIMUM:
6181 case TargetOpcode::G_FMAXIMUM:
6182 PropagateNaN =
true;
6186 auto MatchNaN = [&](
unsigned Idx) {
6191 IdxToPropagate = PropagateNaN ?
Idx : (
Idx == 1 ? 2 : 1);
6195 return MatchNaN(1) || MatchNaN(2);
6199 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6209 Reg == MaybeSameReg;
6244 std::optional<ValueAndVReg> ShiftAmount;
6275 std::optional<ValueAndVReg> ShiftAmt;
6282 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
6286unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6288 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6289 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6290 "Expected a NaN behaviour?");
6300 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6301 return TargetOpcode::G_FMAXNUM;
6302 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6303 return TargetOpcode::G_FMAXIMUM;
6304 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6305 return TargetOpcode::G_FMAXNUM;
6306 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6307 return TargetOpcode::G_FMAXIMUM;
6313 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6314 return TargetOpcode::G_FMINNUM;
6315 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6316 return TargetOpcode::G_FMINIMUM;
6317 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6318 return TargetOpcode::G_FMINNUM;
6319 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6321 return TargetOpcode::G_FMINIMUM;
6325CombinerHelper::SelectPatternNaNBehaviour
6327 bool IsOrderedComparison)
const {
6331 if (!LHSSafe && !RHSSafe)
6332 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
6333 if (LHSSafe && RHSSafe)
6334 return SelectPatternNaNBehaviour::RETURNS_ANY;
6337 if (IsOrderedComparison)
6338 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
6339 : SelectPatternNaNBehaviour::RETURNS_OTHER;
6342 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
6343 : SelectPatternNaNBehaviour::RETURNS_NAN;
6365 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
6367 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
6369 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
6372 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
6373 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
6374 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
6375 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
6377 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
6380 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
6381 if (!Opc || !
isLegal({Opc, {DstTy}}))
6385 if (Opc != TargetOpcode::G_FMAXIMUM && Opc != TargetOpcode::G_FMINIMUM) {
6390 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
6392 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
6397 B.buildInstr(Opc, {Dst}, {CmpLHS, CmpRHS});
6405 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
6412 Register TrueVal =
MI.getOperand(2).getReg();
6413 Register FalseVal =
MI.getOperand(3).getReg();
6414 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
6419 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
6432 if (MatchedSub &&
X != OpLHS)
6440 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
6444 B.buildICmp(Pred, Dst,
Y, Zero);
6450 Register ShiftReg =
MI.getOperand(2).getReg();
6452 auto IsShiftTooBig = [&](
const Constant *
C) {
6453 auto *CI = dyn_cast<ConstantInt>(
C);
6460 unsigned LHSOpndIdx = 1;
6461 unsigned RHSOpndIdx = 2;
6462 switch (
MI.getOpcode()) {
6463 case TargetOpcode::G_UADDO:
6464 case TargetOpcode::G_SADDO:
6465 case TargetOpcode::G_UMULO:
6466 case TargetOpcode::G_SMULO:
6480 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
6485 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
6492 std::optional<FPValueAndVReg> ValAndVReg;
6500 unsigned LHSOpndIdx = 1;
6501 unsigned RHSOpndIdx = 2;
6502 switch (
MI.getOpcode()) {
6503 case TargetOpcode::G_UADDO:
6504 case TargetOpcode::G_SADDO:
6505 case TargetOpcode::G_UMULO:
6506 case TargetOpcode::G_SMULO:
6513 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
6514 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
6515 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
6516 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
6520bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs) {
6523 return isConstantSplatVector(Src, 1, AllowUndefs);
6525 if (AllowUndefs && getOpcodeDef<GImplicitDef>(Src,
MRI) !=
nullptr)
6528 return IConstant && IConstant->Value == 1;
6533bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs) {
6536 return isConstantSplatVector(Src, 0, AllowUndefs);
6538 if (AllowUndefs && getOpcodeDef<GImplicitDef>(Src,
MRI) !=
nullptr)
6541 return IConstant && IConstant->Value == 0;
6548bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
6555 for (
unsigned I = 0;
I < NumSources; ++
I) {
6558 if (ImplicitDef && AllowUndefs)
6560 if (ImplicitDef && !AllowUndefs)
6562 std::optional<ValueAndVReg> IConstant =
6564 if (IConstant && IConstant->Value == SplatValue)
6574CombinerHelper::getConstantOrConstantSplatVector(
Register Src) {
6577 return IConstant->Value;
6581 return std::nullopt;
6584 std::optional<APInt>
Value = std::nullopt;
6585 for (
unsigned I = 0;
I < NumSources; ++
I) {
6586 std::optional<ValueAndVReg> IConstant =
6589 return std::nullopt;
6593 return std::nullopt;
6599bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
6609 for (
unsigned I = 0;
I < NumSources; ++
I) {
6610 std::optional<ValueAndVReg> IConstant =
6619bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
6637 std::optional<ValueAndVReg> TrueOpt =
6639 std::optional<ValueAndVReg> FalseOpt =
6642 if (!TrueOpt || !FalseOpt)
6645 APInt TrueValue = TrueOpt->Value;
6646 APInt FalseValue = FalseOpt->Value;
6651 B.setInstrAndDebugLoc(*
Select);
6652 B.buildZExtOrTrunc(Dest,
Cond);
6660 B.setInstrAndDebugLoc(*
Select);
6661 B.buildSExtOrTrunc(Dest,
Cond);
6669 B.setInstrAndDebugLoc(*
Select);
6671 B.buildNot(Inner,
Cond);
6672 B.buildZExtOrTrunc(Dest, Inner);
6680 B.setInstrAndDebugLoc(*
Select);
6682 B.buildNot(Inner,
Cond);
6683 B.buildSExtOrTrunc(Dest, Inner);
6689 if (TrueValue - 1 == FalseValue) {
6691 B.setInstrAndDebugLoc(*
Select);
6693 B.buildZExtOrTrunc(Inner,
Cond);
6694 B.buildAdd(Dest, Inner, False);
6700 if (TrueValue + 1 == FalseValue) {
6702 B.setInstrAndDebugLoc(*
Select);
6704 B.buildSExtOrTrunc(Inner,
Cond);
6705 B.buildAdd(Dest, Inner, False);
6713 B.setInstrAndDebugLoc(*
Select);
6715 B.buildZExtOrTrunc(Inner,
Cond);
6718 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
6719 B.buildShl(Dest, Inner, ShAmtC, Flags);
6726 B.setInstrAndDebugLoc(*
Select);
6728 B.buildSExtOrTrunc(Inner,
Cond);
6729 B.buildOr(Dest, Inner, False, Flags);
6737 B.setInstrAndDebugLoc(*
Select);
6739 B.buildNot(Not,
Cond);
6741 B.buildSExtOrTrunc(Inner, Not);
6742 B.buildOr(Dest, Inner, True, Flags);
6751bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
6768 if (CondTy != TrueTy)
6773 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
6775 B.setInstrAndDebugLoc(*
Select);
6777 B.buildZExtOrTrunc(Ext,
Cond);
6778 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
6779 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
6786 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
6788 B.setInstrAndDebugLoc(*
Select);
6790 B.buildZExtOrTrunc(Ext,
Cond);
6791 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
6792 B.buildAnd(DstReg, Ext, FreezeTrue);
6798 if (isOneOrOneSplat(False,
true)) {
6800 B.setInstrAndDebugLoc(*
Select);
6803 B.buildNot(Inner,
Cond);
6806 B.buildZExtOrTrunc(Ext, Inner);
6807 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
6808 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
6814 if (isZeroOrZeroSplat(True,
true)) {
6816 B.setInstrAndDebugLoc(*
Select);
6819 B.buildNot(Inner,
Cond);
6822 B.buildZExtOrTrunc(Ext, Inner);
6823 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
6824 B.buildAnd(DstReg, Ext, FreezeFalse);
6855 Register CmpLHS = Cmp->getLHSReg();
6856 Register CmpRHS = Cmp->getRHSReg();
6859 if (True == CmpRHS && False == CmpLHS) {
6867 if (True != CmpLHS || False != CmpRHS)
6907 if (tryFoldSelectOfConstants(
Select, MatchInfo))
6910 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
6920bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
GLogicalBinOp *Logic,
6922 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
6923 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
6927 unsigned Flags = Logic->
getFlags();
6930 GICmp *Cmp1 = getOpcodeDef<GICmp>(LHS,
MRI);
6935 GICmp *Cmp2 = getOpcodeDef<GICmp>(RHS,
MRI);
6946 std::optional<ValueAndVReg> MaybeC1 =
6950 C1 = MaybeC1->Value;
6952 std::optional<ValueAndVReg> MaybeC2 =
6956 C2 = MaybeC2->Value;
6977 std::optional<APInt> Offset1;
6978 std::optional<APInt> Offset2;
6980 if (
GAdd *
Add = getOpcodeDef<GAdd>(R1,
MRI)) {
6981 std::optional<ValueAndVReg> MaybeOffset1 =
6984 R1 =
Add->getLHSReg();
6985 Offset1 = MaybeOffset1->Value;
6989 std::optional<ValueAndVReg> MaybeOffset2 =
6992 R2 =
Add->getLHSReg();
6993 Offset2 = MaybeOffset2->Value;
7012 bool CreateMask =
false;
7025 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7038 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7048 if (CreateMask &&
Offset != 0) {
7049 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7050 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7051 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7052 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7053 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7054 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7055 B.buildZExtOrTrunc(DstReg, ICmp);
7056 }
else if (CreateMask &&
Offset == 0) {
7057 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7058 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7059 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7060 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7061 B.buildZExtOrTrunc(DstReg, ICmp);
7062 }
else if (!CreateMask &&
Offset != 0) {
7063 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7064 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7065 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7066 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7067 B.buildZExtOrTrunc(DstReg, ICmp);
7068 }
else if (!CreateMask &&
Offset == 0) {
7069 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7070 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7071 B.buildZExtOrTrunc(DstReg, ICmp);
7079bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7085 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7088 GFCmp *Cmp1 = getOpcodeDef<GFCmp>(LHS,
MRI);
7093 GFCmp *Cmp2 = getOpcodeDef<GFCmp>(RHS,
MRI);
7103 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7117 if (LHS0 == RHS1 && LHS1 == RHS0) {
7123 if (LHS0 == RHS0 && LHS1 == RHS1) {
7127 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7134 auto False =
B.buildConstant(CmpTy, 0);
7135 B.buildZExtOrTrunc(DestReg, False);
7142 B.buildZExtOrTrunc(DestReg, True);
7144 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7145 B.buildZExtOrTrunc(DestReg, Cmp);
7157 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7160 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7169 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7172 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7186 bool IsSigned =
Add->isSigned();
7195 B.buildUndef(Carry);
7201 if (isConstantOrConstantVectorI(
LHS) && !isConstantOrConstantVectorI(
RHS)) {
7204 B.buildSAddo(Dst, Carry,
RHS,
LHS);
7210 B.buildUAddo(Dst, Carry,
RHS,
LHS);
7215 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(
LHS);
7216 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(
RHS);
7222 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7223 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7225 B.buildConstant(Dst, Result);
7226 B.buildConstant(Carry, Overflow);
7234 B.buildCopy(Dst,
LHS);
7235 B.buildConstant(Carry, 0);
7247 std::optional<APInt> MaybeAddRHS =
7248 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
7251 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
7252 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
7256 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7257 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7263 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7264 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7289 B.buildConstant(Carry, 0);
7297 B.buildConstant(Carry, 1);
7312 B.buildConstant(Carry, 0);
7328 B.buildConstant(Carry, 0);
7336 B.buildConstant(Carry, 1);
7353 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
7358 auto [Dst,
Base] =
MI.getFirst2Regs();
7364 MI.removeFromParent();
7376 std::optional<SrcOp> Res;
7378 while (ExpVal > 0) {
7397 MI.eraseFromParent();
7411 if (DstTy == SrcTy) {
7444 if (DstTy == SrcTy) {
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu AMDGPU Register Bank Select
This file declares a class to represent arbitrary precision floating point values and provide a varie...
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 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 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...
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
Rewrite Partial Register Uses
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...
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.
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
uint64_t IntrinsicInst * II
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
const SmallVectorImpl< MachineOperand > & Cond
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
This file implements the SmallBitVector 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.
uint64_t getZExtValue() const
Get zero extended value.
APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
APInt trunc(unsigned width) const
Truncate to new 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.
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.
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.
APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
unsigned countl_one() const
Count the number of leading one bits.
APInt multiplicativeInverse() const
bool isMask(unsigned numBits) const
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
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.
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.
AttributeSet getAttributes(unsigned Index) const
The attributes for the specified index are returned.
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)
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 bool isOrdered(Predicate predicate)
Determine if the predicate is an ordered operation.
void applyUDivByConst(MachineInstr &MI)
void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal)
bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops)
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
bool matchPtrAddZero(MachineInstr &MI)
}
bool matchAllExplicitUsesAreUndef(MachineInstr &MI)
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx)
Delete MI and replace all of its uses with its OpIdx-th operand.
const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo)
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
bool matchUDivByConst(MachineInstr &MI)
Combine G_UDIV by constant into a multiply by magic constant.
void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg)
bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI)
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
bool matchShiftsTooBig(MachineInstr &MI)
Match shifts greater or equal to the bitwidth of the operation.
bool tryCombineCopy(MachineInstr &MI)
If MI is COPY, try to combine it.
bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo)
bool matchUndefStore(MachineInstr &MI)
Return true if a G_STORE instruction MI is storing an undef value.
bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform: (X + Y) == X -> Y == 0 (X - Y) == X -> Y == 0 (X ^ Y) == X -> Y == 0 (X + Y) !...
bool matchRedundantSExtInReg(MachineInstr &MI)
bool matchSextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine sext of trunc.
bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo)
bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent)
Match FPOWI if it's safe to extend it into a series of multiplications.
bool matchSubAddSameReg(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform: (x + y) - y -> x (x + y) - x -> y x - (y + x) -> 0 - y x - (x + z) -> 0 - z.
bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo)
Do constant FP folding when opportunities are exposed after MIR building.
void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal)
void applyCombineUnmergeZExtToZExt(MachineInstr &MI)
void applyCommuteBinOpOperands(MachineInstr &MI)
bool matchBinOpSameVal(MachineInstr &MI)
Optimize (x op x) -> x.
void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts)
bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
bool matchCombineCopy(MachineInstr &MI)
bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx)
Return true if a G_SELECT instruction MI has a constant comparison.
void eraseInst(MachineInstr &MI)
Erase MI.
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 matchCombineFAddFMAFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y, (fma u, v, z)) (fadd (fmad x,...
void applySimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo)
bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops)
If MI is G_CONCAT_VECTORS, try to combine it.
bool matchAddSubSameReg(MachineInstr &MI, Register &Src)
Transform G_ADD(x, G_SUB(y, x)) to y.
void applyRotateOutOfRange(MachineInstr &MI)
bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: (G_UMULO x, 2) -> (G_UADDO x, x) (G_SMULO x, 2) -> (G_SADDO x, x)
bool matchRotateOutOfRange(MachineInstr &MI)
void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst)
void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo)
void applyCombineShuffleVector(MachineInstr &MI, const ArrayRef< Register > Ops)
Replace MI with a concat_vectors with Ops.
const TargetLowering & getTargetLowering() const
void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo)
Use a function which takes in a MachineIRBuilder to perform a combine.
void applyPtrAddZero(MachineInstr &MI)
bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo)
void setRegBank(Register Reg, const RegisterBank *RegBank)
Set the register bank of Reg.
bool matchRedundantAnd(MachineInstr &MI, Register &Replacement)
void replaceInstWithConstant(MachineInstr &MI, int64_t C)
Replace an instruction with a G_CONSTANT with value C.
bool matchAshrShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo)
Match ashr (shl x, C), C -> sext_inreg (C)
bool tryCombineExtendingLoads(MachineInstr &MI)
If MI is extend that consumes the result of a load, try to combine it.
bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount)
bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo)
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
void applySDivByConst(MachineInstr &MI)
bool matchUndefSelectCmp(MachineInstr &MI)
Return true if a G_SELECT instruction MI has an undef comparison.
void replaceInstWithUndef(MachineInstr &MI)
Replace an instruction with a G_IMPLICIT_DEF.
bool matchRedundantOr(MachineInstr &MI, Register &Replacement)
bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx)
Check if operand OpIdx is undef.
void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo)
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst)
void replaceInstWithFConstant(MachineInstr &MI, double C)
Replace an instruction with a G_FCONSTANT with value C.
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo)
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2)
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo)
Fold (shift (shift base, x), y) -> (shift base (x+y))
bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo)
void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo)
void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond)
bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: (G_*MULO x, 0) -> 0 + no carry out.
void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement)
Delete MI and replace all of its uses with Replacement.
bool matchFunnelShiftToRotate(MachineInstr &MI)
Match an FSHL or FSHR that can be combined to a ROTR or ROTL rotate.
bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate)
Combine inverting a result of a compare into the opposite cond code.
void applyCombineExtOfExt(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo)
void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
bool matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI, unsigned OpIdx)
Check if operand OpIdx is known to be a power of 2.
void applyCombineCopy(MachineInstr &MI)
void applyCombineTruncOfExt(MachineInstr &MI, std::pair< Register, unsigned > &MatchInfo)
bool matchAnyExplicitUseIsUndef(MachineInstr &MI)
Return true if any explicit use operand on MI is defined by a G_IMPLICIT_DEF.
bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo)
void applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute)
bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo)
void applyCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops)
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
bool matchSextTruncSextLoad(MachineInstr &MI)
bool matchShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo)
If we have a shift-by-constant of a bitwise logic op that itself has a shift-by-constant operand with...
bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo)
void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo)
MachineInstr * buildSDivUsingMul(MachineInstr &MI)
Given an G_SDIV MI expressing a signed divide by constant, return an expression that implements it by...
void applySDivByPow2(MachineInstr &MI)
void applyFunnelShiftConstantModulo(MachineInstr &MI)
Replaces the shift amount in MI with ShiftAmt % BW.
bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo)
Do constant folding when opportunities are exposed after MIR building.
bool isPreLegalize() const
bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo)
Match (and (load x), mask) -> zextload x.
bool matchConstantOp(const MachineOperand &MOP, int64_t C)
Return true if MOP is defined by a G_CONSTANT or splat with a value equal to C.
bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine ands.
void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg)
void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate)
void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo)
bool matchConstantFPOp(const MachineOperand &MOP, double C)
Return true if MOP is defined by a G_FCONSTANT or splat with a value exactly equal to C.
bool matchSimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo)
Return true if MI is a G_ADD which can be simplified to a G_SUB.
bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0)
Optimize memcpy intrinsics et al, e.g.
bool matchSelectSameVal(MachineInstr &MI)
Optimize (cond ? x : x) -> x.
void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst)
Transform fp_instr(cst) to constant result of the fp operation.
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo)
bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo)
Try to reassociate to reassociate operands of a commutative binop.
bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
bool tryEmitMemcpyInline(MachineInstr &MI)
Emit loads and stores that perform the given memcpy.
void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo)
bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo)
Fold (xor (and x, y), y) -> (and (not x), y) {.
bool matchCombineFSubFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fsub (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), (fneg z)) (fsub (fpext (fmul x,...
bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info)
bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData)
bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo)
Constant fold G_FMA/G_FMAD.
bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo)
void applyExpandFPowI(MachineInstr &MI, int64_t Exponent)
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
bool isLegal(const LegalityQuery &Query) const
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine selects.
bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts)
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo)
bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg)
Transform anyext(trunc(x)) to x.
void applySimplifyURemByPow2(MachineInstr &MI)
Combine G_UREM x, (known power of 2) to an add and bitmasking.
bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo)
void applyCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops)
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
MachineRegisterInfo & MRI
void applyUMulHToLShr(MachineInstr &MI)
bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo)
Match expression trees of the form.
bool matchShuffleToExtract(MachineInstr &MI)
bool matchUndefShuffleVectorMask(MachineInstr &MI)
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI)
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal)
Transform a multiply by a power-of-2 value to a left shift.
bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo)
SelectOperand is the operand in binary operator MI that is the select to fold.
bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo)
bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fadd x, fneg(y)) -> (fsub x, y) (fadd fneg(x), y) -> (fsub y, x) (fsub x,...
bool matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo)
Fold away a merge of an unmerge of the corresponding values.
void applyCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo)
bool matchCombineUnmergeZExtToZExt(MachineInstr &MI)
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI)
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx)
Checks if constant at ConstIdx is larger than MI 's bitwidth.
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelKnownBits *KB=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
bool matchCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI)
Try to combine G_[SU]DIV and G_[SU]REM into a single G_[SU]DIVREM when their source operands are iden...
bool matchCombineTruncOfExt(MachineInstr &MI, std::pair< Register, unsigned > &MatchInfo)
Transform trunc ([asz]ext x) to x or ([asz]ext x) or (trunc x).
bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI)
Returns true if DefMI precedes UseMI or they are the same instruction.
bool matchDivByPow2(MachineInstr &MI, bool IsSigned)
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg)
bool matchUMulHToLShr(MachineInstr &MI)
bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI)
Returns true if DefMI dominates UseMI.
MachineInstr * buildUDivUsingMul(MachineInstr &MI)
Given an G_UDIV MI expressing a divide by constant, return an expression that implements it by multip...
bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg)
Transform zext(trunc(x)) to x.
void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData)
bool matchNonNegZext(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine zext nneg to sext.
bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false)
bool matchZextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine zext of trunc.
void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI)
void applyShuffleToExtract(MachineInstr &MI)
MachineDominatorTree * MDT
bool matchSDivByConst(MachineInstr &MI)
void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo)
bool matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands)
Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo)
void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo)
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo)
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
const RegisterBankInfo * RBI
bool matchCommuteShift(MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo)
void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI)
const TargetRegisterInfo * TRI
bool tryCombineShuffleVector(MachineInstr &MI)
Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS.
bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg)
Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo)
GISelChangeObserver & Observer
bool matchCombineExtOfExt(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo)
Transform [asz]ext([asz]ext(x)) to [asz]ext x.
bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo)
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo)
Match sext_inreg(load p), imm -> sextload p.
bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo)
bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute)
Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) Transform G_ADD y,...
bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine ors.
void applyFunnelShiftToRotate(MachineInstr &MI)
void applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands)
bool matchOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond)
If a brcond's true block is not the fallthrough, make it so by inverting the condition and swapping o...
bool matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: (G_*ADDE x, y, 0) -> (G_*ADDO x, y) (G_*SUBE x, y, 0) -> (G_*SUBO x, y)
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine addos.
void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg)
Transform PtrToInt(IntToPtr(x)) to x.
bool matchCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftSize, unsigned &ShiftVal)
Reduce a shift by a constant to an unmerge and a shift on a half sized type.
bool matchCommuteConstantToRHS(MachineInstr &MI)
Match constant LHS ops that should be commuted.
void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo)
void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI)
void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo)
void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo)
Replace MI with a series of instructions described in MatchInfo.
bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
MachineIRBuilder & Builder
bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine select to integer min/max.
bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: shr (and x, n), k -> ubfx x, pos, width.
bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops)
bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo)
Reassociate commutative binary operations like G_ADD.
bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo)
Push a binary operator through a select on constants.
bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo)
Do constant folding when opportunities are exposed after MIR building.
bool matchOperandIsZero(MachineInstr &MI, unsigned OpIdx)
Check if operand OpIdx is zero.
bool matchOrShiftToFunnelShift(MachineInstr &MI, BuildFnTy &MatchInfo)
void applyUDivByPow2(MachineInstr &MI)
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo)
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo)
void applySextTruncSextLoad(MachineInstr &MI)
bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo)
bool matchCommuteFPConstantToRHS(MachineInstr &MI)
Match constant LHS FP ops that should be commuted.
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.
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...
ConstantRange subtract(const APInt &CI) const
Subtract the specified constant from the endpoints of this constant range.
static 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.
OverflowResult unsignedAddMayOverflow(const ConstantRange &Other) const
Return whether unsigned add of the two ranges always/never overflows.
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 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...
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.
This is an important base class in LLVM.
This class represents an Operation in the Expression.
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 getLHSReg() const
Register getRHSReg() const
Represents a G_BUILD_VECTOR.
Register getSrcReg() const
Abstract class that contains various methods for clients to notify about changes.
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
void finishedChangingAllUsesOfReg()
All instructions reported as changing by changingAllUsesOfReg() have finished being changed.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
virtual void erasingInstr(MachineInstr &MI)=0
An instruction is about to be erased.
void changingAllUsesOfReg(const MachineRegisterInfo &MRI, Register Reg)
All the instructions using the given register are being changed.
unsigned computeNumSignBits(Register R, const APInt &DemandedElts, unsigned Depth=0)
KnownBits getKnownBits(Register R)
APInt getKnownZeroes(Register R)
Simple wrapper observer that takes several observers, and calls each one for each event.
Represents a G_IMPLICIT_DEF.
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
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
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 unsigned getAddressSpace() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
constexpr LLT getScalarType() const
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
This is an important class for using LLVM in a threaded context.
@ Legalized
Instruction has been legalized and the MachineFunction changed.
LegalizeResult lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0)
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...
bool isLegalOrCustom(const LegalityQuery &Query) const
LegalizeActionStep getAction(const LegalityQuery &Query) const
Determine what action should be taken to legalize the described instruction.
TypeSize getValue() const
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
bool isLayoutSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB will be emitted immediately after this block, such that if this bloc...
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
bool dominates(const MachineDomTreeNode *A, const MachineDomTreeNode *B) const
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.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
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.
MachineInstrBuilder buildFMul(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder insertInstr(MachineInstrBuilder MIB)
Insert an existing instruction at the insertion point.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
LLVMContext & getContext() const
MachineInstrBuilder buildAdd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ADD Op0, Op1.
MachineInstrBuilder buildUndef(const DstOp &Res)
Build and insert Res = IMPLICIT_DEF.
MachineInstrBuilder buildNot(const DstOp &Dst, const SrcOp &Src0)
Build and insert a bitwise not, NegOne = G_CONSTANT -1 Res = G_OR Op0, NegOne.
MachineInstrBuilder buildCTTZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTTZ Op0, Src0.
MachineInstrBuilder buildAShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildUnmerge(ArrayRef< LLT > Res, const SrcOp &Op)
Build and insert Res0, ... = G_UNMERGE_VALUES Op.
MachineInstrBuilder buildSelect(const DstOp &Res, const SrcOp &Tst, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_SELECT Tst, Op0, Op1.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1)
Build and insert a Res = G_ICMP Pred, Op0, Op1.
MachineInstrBuilder buildCast(const DstOp &Dst, const SrcOp &Src)
Build and insert an appropriate cast between two registers of equal size.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildURem(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_UREM Op0, Op1.
MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildConcatVectors(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_CONCAT_VECTORS Op0, ...
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 buildIntToPtr(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_INTTOPTR instruction.
MachineInstrBuilder buildBuildVector(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ...
MachineInstrBuilder buildNeg(const DstOp &Dst, const SrcOp &Src0)
Build and insert integer negation Zero = G_CONSTANT 0 Res = G_SUB Zero, Op0.
MachineInstrBuilder buildCTLZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTLZ Op0, Src0.
MachineInstrBuilder buildFDiv(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_FDIV Op0, Op1.
MachineInstrBuilder buildMergeLikeInstr(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_MERGE_VALUES Op0, ... or Res = G_BUILD_VECTOR Op0, ... or Res = G_CONCAT_VEC...
MachineInstrBuilder buildPtrAdd(const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_PTR_ADD Op0, Op1.
MachineInstrBuilder buildZExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ZEXT Op, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes...
MachineInstrBuilder buildExtractVectorElementConstant(const DstOp &Res, const SrcOp &Val, const int Idx)
Build and insert Res = G_EXTRACT_VECTOR_ELT Val, Idx.
virtual MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val)
Build and insert Res = G_FCONSTANT Val.
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
MachineInstrBuilder buildExtOrTrunc(unsigned ExtOpc, const DstOp &Res, const SrcOp &Op)
Build and insert Res = ExtOpc, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes of...
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
void setDebugLoc(const DebugLoc &DL)
Set the debug location to DL for all the next build instructions.
MachineInstrBuilder buildFNeg(const DstOp &Dst, const SrcOp &Src0, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_FNEG Op0.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
MachineInstrBuilder buildInstrNoInsert(unsigned Opcode)
Build but don't insert <empty> = Opcode <empty>.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
MachineInstrBuilder buildLoadInstr(unsigned Opcode, const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = <opcode> Addr, MMO.
MachineInstrBuilder buildXor(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_XOR Op0, Op1.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
MachineInstrBuilder buildFCanonicalize(const DstOp &Dst, const SrcOp &Src0, std::optional< unsigned > Flags=std::nullopt)
Build and insert Dst = G_FCANONICALIZE Src0.
MachineInstrBuilder buildSExtInReg(const DstOp &Res, const SrcOp &Op, int64_t ImmOp)
Build and insert Res = G_SEXT_INREG Op, ImmOp.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
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
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.
iterator_range< mop_iterator > uses()
Returns a range that includes all operands that are register uses.
void cloneMemRefs(MachineFunction &MF, const MachineInstr &MI)
Clone another MachineInstr's memory reference descriptor list and replace ours with it.
unsigned getNumOperands() const
Retuns the total number of operands.
void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
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.
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
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
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,...
bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
use_instr_iterator use_instr_begin(Register RegNo) const
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
const RegClassOrRegBank & getRegClassOrRegBank(Register Reg) const
Return the register bank or register class of Reg.
void setRegClassOrRegBank(Register Reg, const RegClassOrRegBank &RCOrRB)
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
iterator_range< use_instr_iterator > use_instructions(Register Reg) const
Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
bool constrainRegAttrs(Register Reg, Register ConstrainingReg, unsigned MinNumRegs=0)
Constrain the register class or the register bank of the virtual register Reg (and low-level type) to...
iterator_range< use_iterator > use_operands(Register Reg) const
void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
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.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
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 isExtendLikelyToBeFolded(MachineInstr &ExtMI, MachineRegisterInfo &MRI) const
Given the generic extension instruction ExtMI, returns true if this extension is a likely candidate f...
virtual bool produceSameValue(const MachineInstr &MI0, const MachineInstr &MI1, const MachineRegisterInfo *MRI=nullptr) const
Return true if two machine instructions would produce identical values.
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 bool isReassocProfitable(SelectionDAG &DAG, SDValue N0, SDValue N1) const
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.
LLVM Value Representation.
Value(Type *Ty, unsigned scid)
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...
operand_type_match m_Reg()
SpecificConstantOrSplatMatch m_SpecificICstOrSplat(int64_t RequestedValue)
Matches a RequestedValue constant or a constant splat of RequestedValue.
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false > m_GBuildVector(const LHS &L, const RHS &R)
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
SpecificConstantMatch m_SpecificICst(int64_t RequestedValue)
Matches a constant equal to RequestedValue.
operand_type_match m_Pred()
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)
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
CheckType m_SpecificType(LLT Ty)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FADD, true > m_GFAdd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_PTRTOINT > m_GPtrToInt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
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_LSHR, false > m_GLShr(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ANYEXT > m_GAnyExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
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.
BinaryOp_match< cst_pred_ty< is_zero_int >, ValTy, Instruction::Sub > m_Neg(const ValTy &V)
Matches a 'Neg' as 'sub 0, V'.
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.
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...
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.
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)
const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
EVT getApproximateEVTForLLT(LLT Ty, const DataLayout &DL, LLVMContext &Ctx)
std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
std::optional< APInt > getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI)
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...
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
std::optional< APFloat > ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
bool isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL, bool OrZero=false, unsigned Depth=0, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true)
Return true if the given value is known to have exactly one bit set when defined.
std::optional< APInt > isConstantOrConstantSplatVector(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a constant integer or a splat vector of constant integers.
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...
MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
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...
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...
std::function< void(MachineIRBuilder &)> BuildFnTy
std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
bool isConstantOrConstantVector(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowFP=true, bool AllowOpaqueConstants=true)
Return true if the specified instruction is known to be a constant, or a vector of constants.
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
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...
bool canCreateUndefOrPoison(const Operator *Op, bool ConsiderFlagsAndMetadata=true)
canCreateUndefOrPoison returns true if Op can create undef or poison from non-undef & non-poison oper...
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
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.
std::optional< APInt > ConstantFoldCastOp(unsigned Opcode, LLT DstTy, const Register Op0, const MachineRegisterInfo &MRI)
@ Xor
Bitwise or logical XOR of integers.
DWARFExpression::Operation Op
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.
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
int64_t getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP)
Returns an integer representing true, as defined by the TargetBooleanContents.
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.
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.
bool isKnownNeverNaN(const Value *V, unsigned Depth, const SimplifyQuery &SQ)
Return true if the floating-point scalar value is not a NaN or if the floating-point vector value has...
Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
unsigned getFCmpCode(CmpInst::Predicate CC)
Similar to getICmpCode but for FCmpInst.
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 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.
static std::optional< bool > eq(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_EQ result.
bool isUnknown() const
Returns true if we don't know any bits.
static std::optional< bool > ne(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_NE result.
static std::optional< bool > sge(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_SGE result.
unsigned countMinLeadingZeros() const
Returns the minimum number of leading zero bits.
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.
static std::optional< bool > ugt(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_UGT result.
static std::optional< bool > slt(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_SLT result.
static std::optional< bool > ult(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_ULT result.
static std::optional< bool > ule(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_ULE result.
static std::optional< bool > sle(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_SLE result.
static std::optional< bool > sgt(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_SGT result.
static std::optional< bool > uge(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_UGE result.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
LegalizeAction Action
The action to take or the final answer.
This class contains a discriminated union of information about pointers in memory operands,...
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
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 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