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()) {
86 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
105 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
106 return ByteWidth -
I - 1;
126static std::optional<bool>
130 unsigned Width = MemOffset2Idx.
size();
133 bool BigEndian =
true, LittleEndian =
true;
134 for (
unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
135 auto MemOffsetAndIdx = MemOffset2Idx.
find(MemOffset);
136 if (MemOffsetAndIdx == MemOffset2Idx.
end())
138 const int64_t
Idx = MemOffsetAndIdx->second - LowestIdx;
139 assert(
Idx >= 0 &&
"Expected non-negative byte offset?");
142 if (!BigEndian && !LittleEndian)
146 assert((BigEndian != LittleEndian) &&
147 "Pattern cannot be both big and little endian!");
154 assert(
LI &&
"Must have LegalizerInfo to query isLegal!");
170 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
171 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
198 unsigned ToOpcode)
const {
224 if (
MI.getOpcode() != TargetOpcode::COPY)
234 MI.eraseFromParent();
255 if (OrigDef->
isPHI() || isa<GUnmerge>(OrigDef))
262 std::optional<MachineOperand> MaybePoisonOperand;
264 if (!Operand.isReg())
270 if (!MaybePoisonOperand)
271 MaybePoisonOperand = Operand;
280 if (!MaybePoisonOperand) {
283 cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
285 B.buildCopy(
DstOp, OrigOp);
290 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
291 LLT MaybePoisonOperandRegTy =
MRI.
getType(MaybePoisonOperandReg);
295 cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
298 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
309 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
310 "Invalid instruction");
320 assert(Def &&
"Operand not defined");
323 switch (Def->getOpcode()) {
324 case TargetOpcode::G_BUILD_VECTOR:
331 case TargetOpcode::G_IMPLICIT_DEF: {
340 "All undefs should have the same type");
344 EltIdx != EltEnd; ++EltIdx)
345 Ops.
push_back(Undef->getOperand(0).getReg());
356 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.
getType(Ops[0])}})) {
384 MI.eraseFromParent();
394 if (!ConcatMI1 || !ConcatMI2)
398 if (
MRI.
getType(ConcatMI1->getSourceReg(0)) !=
405 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
409 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
410 if (i + j >= Mask.size())
412 if (Mask[i + j] != -1)
416 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
419 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
420 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
421 if (i + j >= Mask.size())
423 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
429 Ops.
push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
431 Ops.
push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
432 ConcatMI1->getNumSources()));
440 {TargetOpcode::G_CONCAT_VECTORS,
441 {
MRI.
getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
454 assert(SrcTy.
isValid() &&
"Unexpected full undef vector in concat combine");
470 MI.eraseFromParent();
484 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
485 "Invalid instruction kind");
510 if (DstNumElts < 2 * SrcNumElts && DstNumElts != 1)
515 if (DstNumElts % SrcNumElts != 0)
521 unsigned NumConcat = DstNumElts / SrcNumElts;
524 for (
unsigned i = 0; i != DstNumElts; ++i) {
531 if ((
Idx % SrcNumElts != (i % SrcNumElts)) ||
532 (ConcatSrcs[i / SrcNumElts] >= 0 &&
533 ConcatSrcs[i / SrcNumElts] != (
int)(
Idx / SrcNumElts)))
536 ConcatSrcs[i / SrcNumElts] =
Idx / SrcNumElts;
543 for (
auto Src : ConcatSrcs) {
570 MI.eraseFromParent();
574 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
575 "Invalid instruction kind");
578 return Mask.size() == 1;
585 int I =
MI.getOperand(3).getShuffleMask()[0];
590 if (
I >= Src1NumElts) {
591 SrcReg =
MI.getOperand(2).getReg();
603 MI.eraseFromParent();
612 const LLT TyForCandidate,
613 unsigned OpcodeForCandidate,
618 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
629 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
632 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
633 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
634 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
640 if (!isa<GZExtLoad>(LoadMI) && CurrentUse.
Ty == TyForCandidate) {
642 OpcodeForCandidate == TargetOpcode::G_ZEXT)
644 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
645 OpcodeForCandidate == TargetOpcode::G_SEXT)
646 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
655 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
666static void InsertInsnsWithoutSideEffectsBeforeUse(
678 InsertBB = PredBB->
getMBB();
683 if (InsertBB ==
DefMI.getParent()) {
685 Inserter(InsertBB, std::next(InsertPt), UseMO);
704 unsigned CandidateLoadOpc;
706 case TargetOpcode::G_ANYEXT:
707 CandidateLoadOpc = TargetOpcode::G_LOAD;
709 case TargetOpcode::G_SEXT:
710 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
712 case TargetOpcode::G_ZEXT:
713 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
718 return CandidateLoadOpc;
749 if (!llvm::has_single_bit<uint32_t>(LoadValueTy.
getSizeInBits()))
757 unsigned PreferredOpcode =
759 ? TargetOpcode::G_ANYEXT
760 : isa<GSExtLoad>(&
MI) ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
761 Preferred = {
LLT(), PreferredOpcode,
nullptr};
763 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
764 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
765 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
766 const auto &MMO = LoadMI->
getMMO();
776 if (
LI->
getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
780 Preferred = ChoosePreferredUse(
MI, Preferred,
791 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
809 if (PreviouslyEmitted) {
819 EmittedInsns[InsertIntoBB] = NewMI;
831 Uses.push_back(&UseMO);
833 for (
auto *UseMO :
Uses) {
843 if (UseDstReg != ChosenDstReg) {
844 if (Preferred.
Ty == UseDstTy) {
881 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
896 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
899 MI.getOperand(0).setReg(ChosenDstReg);
905 assert(
MI.getOpcode() == TargetOpcode::G_AND);
924 APInt MaskVal = MaybeMask->Value;
945 if (MaskSizeBits > LoadSizeBits.
getValue())
965 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
971 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.
getType(PtrReg)}, {MemDesc}}))
975 B.setInstrAndDebugLoc(*LoadMI);
976 auto &MF =
B.getMF();
978 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
979 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
988 "shouldn't consider debug uses");
996 if (DefOrUse ==
MBB.
end())
998 return &*DefOrUse == &
DefMI;
1004 "shouldn't consider debug uses");
1007 else if (
DefMI.getParent() !=
UseMI.getParent())
1014 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1023 LoadUser = TruncSrc;
1025 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1028 if (
auto *LoadMI = getOpcodeDef<GSExtLoad>(LoadUser,
MRI)) {
1030 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1034 if (LoadSizeBits == SizeInBits)
1041 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1043 MI.eraseFromParent();
1047 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1048 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1058 auto *LoadDef = getOpcodeDef<GLoad>(SrcReg,
MRI);
1062 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1067 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1070 if (NewSizeBits < 8)
1082 if (LoadDef->isSimple())
1084 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1094 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1099 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1100 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1102 unsigned ScalarSizeBits;
1103 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1112 auto &MMO = LoadDef->
getMMO();
1115 auto PtrInfo = MMO.getPointerInfo();
1119 MI.eraseFromParent();
1130 auto *MF =
MI->getMF();
1131 auto *
Addr = getOpcodeDef<GPtrAdd>(
MI->getPointerReg(),
MRI);
1137 AM.
BaseOffs = CstOff->getSExtValue();
1142 MF->getDataLayout(), AM,
1144 MF->getFunction().getContext()),
1145 MI->getMMO().getAddrSpace());
1150 case TargetOpcode::G_LOAD:
1151 return TargetOpcode::G_INDEXED_LOAD;
1152 case TargetOpcode::G_STORE:
1153 return TargetOpcode::G_INDEXED_STORE;
1154 case TargetOpcode::G_ZEXTLOAD:
1155 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1156 case TargetOpcode::G_SEXTLOAD:
1157 return TargetOpcode::G_INDEXED_SEXTLOAD;
1163bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1173 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1174 OpTys = {PtrTy, Ty, Ty};
1176 OpTys = {Ty, PtrTy};
1184 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1185 "considered for post-indexing."));
1189 bool &RematOffset)
const {
1202 if (!isIndexedLoadStoreLegal(LdSt))
1211 unsigned NumUsesChecked = 0;
1216 auto *PtrAdd = dyn_cast<GPtrAdd>(&
Use);
1224 if (StoredValDef == &
Use)
1227 Offset = PtrAdd->getOffsetReg();
1229 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1235 RematOffset =
false;
1239 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1245 if (&BasePtrUse == PtrDef)
1250 auto *BasePtrLdSt = dyn_cast<GLoadStore>(&BasePtrUse);
1251 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1253 isIndexedLoadStoreLegal(*BasePtrLdSt))
1258 if (
auto *BasePtrUseDef = dyn_cast<GPtrAdd>(&BasePtrUse)) {
1259 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1263 if (BaseUseUse.getParent() != LdSt.
getParent())
1266 if (
auto *UseUseLdSt = dyn_cast<GLoadStore>(&BaseUseUse))
1275 Addr = PtrAdd->getReg(0);
1276 Base = PtrAdd->getBaseReg();
1298 if (!isIndexedLoadStoreLegal(LdSt))
1302 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1305 if (
auto *St = dyn_cast<GStore>(&LdSt)) {
1307 if (
Base == St->getValueReg())
1312 if (St->getValueReg() ==
Addr)
1318 if (AddrUse.getParent() != LdSt.
getParent())
1323 bool RealUse =
false;
1330 if (
auto *UseLdSt = dyn_cast<GLoadStore>(&AddrUse)) {
1342 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1345 auto *LoadMI = getOpcodeDef<GLoad>(
MI.getOperand(1).getReg(),
MRI);
1359 if (!LoadMI->isSimple())
1371 const unsigned MaxIter = 20;
1374 if (
II->isLoadFoldBarrier())
1376 if (Iter++ == MaxIter)
1392 int Elt = CVal->getZExtValue();
1405 Register VecPtr = LoadMI->getPointerReg();
1413 LegalityQuery Q = {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}};
1438 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1448 auto &LdSt = cast<GLoadStore>(
MI);
1453 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1455 if (!MatchInfo.
IsPre &&
1456 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1466 unsigned Opcode =
MI.getOpcode();
1467 bool IsStore = Opcode == TargetOpcode::G_STORE;
1475 *OldCst->getOperand(1).getCImm());
1476 MatchInfo.
Offset = NewCst.getReg(0);
1482 MIB.
addUse(
MI.getOperand(0).getReg());
1484 MIB.
addDef(
MI.getOperand(0).getReg());
1492 MI.eraseFromParent();
1500 unsigned Opcode =
MI.getOpcode();
1501 bool IsDiv, IsSigned;
1506 case TargetOpcode::G_SDIV:
1507 case TargetOpcode::G_UDIV: {
1509 IsSigned = Opcode == TargetOpcode::G_SDIV;
1512 case TargetOpcode::G_SREM:
1513 case TargetOpcode::G_UREM: {
1515 IsSigned = Opcode == TargetOpcode::G_SREM;
1521 unsigned DivOpcode, RemOpcode, DivremOpcode;
1523 DivOpcode = TargetOpcode::G_SDIV;
1524 RemOpcode = TargetOpcode::G_SREM;
1525 DivremOpcode = TargetOpcode::G_SDIVREM;
1527 DivOpcode = TargetOpcode::G_UDIV;
1528 RemOpcode = TargetOpcode::G_UREM;
1529 DivremOpcode = TargetOpcode::G_UDIVREM;
1548 if (
MI.getParent() ==
UseMI.getParent() &&
1549 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1550 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1563 unsigned Opcode =
MI.getOpcode();
1564 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1567 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1568 DestDivReg =
MI.getOperand(0).getReg();
1572 DestRemReg =
MI.getOperand(0).getReg();
1576 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1586 : TargetOpcode::G_UDIVREM,
1587 {DestDivReg, DestRemReg},
1589 MI.eraseFromParent();
1595 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1614 assert(std::next(BrIt) ==
MBB->
end() &&
"expected G_BR to be a terminator");
1616 BrCond = &*std::prev(BrIt);
1617 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1623 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1641 MI.getOperand(0).setMBB(FallthroughBB);
1656 return Helper.lowerMemcpyInline(
MI) ==
1661 unsigned MaxLen)
const {
1673 switch (
MI.getOpcode()) {
1676 case TargetOpcode::G_FNEG: {
1677 Result.changeSign();
1680 case TargetOpcode::G_FABS: {
1684 case TargetOpcode::G_FPTRUNC: {
1686 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1691 case TargetOpcode::G_FSQRT: {
1695 Result =
APFloat(sqrt(Result.convertToDouble()));
1698 case TargetOpcode::G_FLOG2: {
1719 MI.eraseFromParent();
1730 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1740 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1753 Type *AccessTy =
nullptr;
1754 auto &MF = *
MI.getMF();
1756 if (
auto *LdSt = dyn_cast<GLoadStore>(&
UseMI)) {
1758 MF.getFunction().getContext());
1763 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1768 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1771 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1772 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1773 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1786 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1792 MI.getOperand(1).setReg(MatchInfo.
Base);
1793 MI.getOperand(2).setReg(NewOffset.getReg(0));
1806 unsigned Opcode =
MI.getOpcode();
1807 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1808 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1809 Opcode == TargetOpcode::G_USHLSAT) &&
1810 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1830 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1835 if (Opcode == TargetOpcode::G_USHLSAT &&
1844 unsigned Opcode =
MI.getOpcode();
1845 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1846 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1847 Opcode == TargetOpcode::G_USHLSAT) &&
1848 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1852 auto Imm = MatchInfo.
Imm;
1854 if (Imm >= ScalarSizeInBits) {
1856 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1858 MI.eraseFromParent();
1863 Imm = ScalarSizeInBits - 1;
1869 MI.getOperand(1).setReg(MatchInfo.
Reg);
1870 MI.getOperand(2).setReg(NewImm);
1886 unsigned ShiftOpcode =
MI.getOpcode();
1887 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1888 ShiftOpcode == TargetOpcode::G_ASHR ||
1889 ShiftOpcode == TargetOpcode::G_LSHR ||
1890 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1891 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1892 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1895 Register LogicDest =
MI.getOperand(1).getReg();
1900 unsigned LogicOpcode = LogicMI->
getOpcode();
1901 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1902 LogicOpcode != TargetOpcode::G_XOR)
1906 const Register C1 =
MI.getOperand(2).getReg();
1908 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1911 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1915 if (
MI->getOpcode() != ShiftOpcode ||
1925 ShiftVal = MaybeImmVal->Value.getSExtValue();
1936 if (matchFirstShift(LogicMIOp1, C0Val)) {
1938 MatchInfo.
Shift2 = LogicMIOp1;
1939 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
1941 MatchInfo.
Shift2 = LogicMIOp2;
1945 MatchInfo.
ValSum = C0Val + C1Val;
1951 MatchInfo.
Logic = LogicMI;
1957 unsigned Opcode =
MI.getOpcode();
1958 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1959 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
1960 Opcode == TargetOpcode::G_SSHLSAT) &&
1961 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1979 Register Shift2Const =
MI.getOperand(2).getReg();
1991 MI.eraseFromParent();
1996 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
1999 auto &Shl = cast<GenericMachineInstr>(
MI);
2019 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2020 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2023 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2024 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2025 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {
S1, S2});
2031 unsigned &ShiftVal)
const {
2032 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2038 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2039 return (
static_cast<int32_t
>(ShiftVal) != -1);
2043 unsigned &ShiftVal)
const {
2044 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2049 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2050 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2058 GSub &Sub = cast<GSub>(
MI);
2071 auto NegCst =
B.buildConstant(Ty, -Imm);
2073 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2074 MI.getOperand(2).setReg(NegCst.getReg(0));
2084 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
KB);
2099 if (!MaybeShiftAmtVal)
2113 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2114 MatchData.
Reg = ExtSrc;
2115 MatchData.
Imm = ShiftAmt;
2119 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2125 int64_t ShiftAmtVal = MatchData.
Imm;
2132 MI.eraseFromParent();
2139 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2142 auto *Unmerge = getOpcodeDef<GUnmerge>(MergedValues[0],
MRI);
2143 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2146 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2147 if (MergedValues[
I] != Unmerge->getReg(
I))
2150 MatchInfo = Unmerge->getSourceReg();
2164 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2165 "Expected an unmerge");
2166 auto &Unmerge = cast<GUnmerge>(
MI);
2169 auto *SrcInstr = getOpcodeDef<GMergeLikeInstr>(SrcReg,
MRI);
2177 if (SrcMergeTy != Dst0Ty && !SameSize)
2181 for (
unsigned Idx = 0;
Idx < SrcInstr->getNumSources(); ++
Idx)
2188 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2189 "Expected an unmerge");
2191 "Not enough operands to replace all defs");
2192 unsigned NumElems =
MI.getNumOperands() - 1;
2196 bool CanReuseInputDirectly = DstTy == SrcTy;
2197 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2209 if (CanReuseInputDirectly)
2214 MI.eraseFromParent();
2219 unsigned SrcIdx =
MI.getNumOperands() - 1;
2220 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2222 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2223 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2234 for (
unsigned Idx = 0;
Idx != SrcIdx; ++
Idx) {
2236 Val = Val.
lshr(ShiftAmt);
2244 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2245 "Expected an unmerge");
2247 "Not enough operands to replace all defs");
2248 unsigned NumElems =
MI.getNumOperands() - 1;
2249 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2254 MI.eraseFromParent();
2260 unsigned SrcIdx =
MI.getNumOperands() - 1;
2261 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2263 unsigned NumElems =
MI.getNumOperands() - 1;
2264 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2266 B.buildUndef(DstReg);
2274 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2275 "Expected an unmerge");
2280 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs();
Idx != EndIdx; ++
Idx) {
2289 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2290 Register Dst0Reg =
MI.getOperand(0).getReg();
2292 MI.eraseFromParent();
2296 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2297 "Expected an unmerge");
2298 Register Dst0Reg =
MI.getOperand(0).getReg();
2305 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2322 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2323 "Expected an unmerge");
2325 Register Dst0Reg =
MI.getOperand(0).getReg();
2330 "Expecting a G_ZEXT");
2340 "ZExt src doesn't fit in destination");
2345 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs();
Idx != EndIdx; ++
Idx) {
2350 MI.eraseFromParent();
2354 unsigned TargetShiftSize,
2355 unsigned &ShiftVal)
const {
2356 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2357 MI.getOpcode() == TargetOpcode::G_LSHR ||
2358 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2366 if (
Size <= TargetShiftSize)
2374 ShiftVal = MaybeImmVal->Value.getSExtValue();
2375 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2384 unsigned HalfSize =
Size / 2;
2385 assert(ShiftVal >= HalfSize);
2390 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2392 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2393 Register Narrowed = Unmerge.getReg(1);
2400 if (NarrowShiftAmt != 0) {
2407 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2408 Register Narrowed = Unmerge.getReg(0);
2413 if (NarrowShiftAmt != 0) {
2421 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2423 HalfTy, Unmerge.getReg(1),
2426 if (ShiftVal == HalfSize) {
2430 }
else if (ShiftVal ==
Size - 1) {
2438 HalfTy, Unmerge.getReg(1),
2447 MI.eraseFromParent();
2463 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2473 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2476 MI.eraseFromParent();
2481 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2484 MI.eraseFromParent();
2489 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2496 PtrReg.second =
false;
2506 PtrReg.second =
true;
2518 const bool DoCommute = PtrReg.second;
2527 MI.eraseFromParent();
2531 APInt &NewCst)
const {
2532 auto &PtrAdd = cast<GPtrAdd>(
MI);
2543 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2552 APInt &NewCst)
const {
2553 auto &PtrAdd = cast<GPtrAdd>(
MI);
2557 PtrAdd.eraseFromParent();
2562 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2567 SrcReg = OriginalSrcReg;
2575 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2593 if (ShiftSize > 32 && TruncSize < 32)
2606 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2607 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2624 case TargetOpcode::G_SHL: {
2633 case TargetOpcode::G_LSHR:
2634 case TargetOpcode::G_ASHR: {
2641 if (
User.getOpcode() == TargetOpcode::G_STORE)
2645 if (NewShiftTy == SrcTy)
2659 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2662 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2667 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2669 LLT NewShiftTy = MatchInfo.second;
2683 if (NewShiftTy == DstTy)
2693 return MO.isReg() &&
2694 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2700 return !MO.isReg() ||
2701 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2706 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2708 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2712 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2713 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2718 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2719 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2725 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2726 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2727 "Expected an insert/extract element op");
2733 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2741 unsigned &OpIdx)
const {
2747 OpIdx = Cst->isZero() ? 3 : 2;
2792 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2819 return MO.isReg() && MO.getReg().isPhysical();
2829 return I1->isIdenticalTo(*I2);
2844 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2856 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2857 MaybeCst->getSExtValue() ==
C;
2864 std::optional<FPValueAndVReg> MaybeCst;
2868 return MaybeCst->Value.isExactlyValue(
C);
2872 unsigned OpIdx)
const {
2873 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2875 Register Replacement =
MI.getOperand(OpIdx).getReg();
2878 MI.eraseFromParent();
2883 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2887 MI.eraseFromParent();
2891 unsigned ConstIdx)
const {
2892 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
2905 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
2906 MI.getOpcode() == TargetOpcode::G_FSHR) &&
2907 "This is not a funnel shift operation");
2909 Register ConstReg =
MI.getOperand(3).getReg();
2914 assert((VRegAndVal) &&
"Value is not a constant");
2917 APInt NewConst = VRegAndVal->Value.
urem(
2922 MI.getOpcode(), {MI.getOperand(0)},
2923 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
2925 MI.eraseFromParent();
2929 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2943 unsigned OpIdx)
const {
2950 unsigned OpIdx)
const {
2952 return MO.
isReg() &&
2957 unsigned OpIdx)
const {
2964 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2966 MI.eraseFromParent();
2971 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2973 MI.eraseFromParent();
2977 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2979 MI.eraseFromParent();
2984 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2986 MI.eraseFromParent();
2990 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2992 MI.eraseFromParent();
2996 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
2999 Register &NewLHS = std::get<0>(MatchInfo);
3000 Register &NewRHS = std::get<1>(MatchInfo);
3008 NewLHS = MaybeNewLHS;
3017 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3030 TargetOpcode::G_INSERT_VECTOR_ELT)
3036 MatchInfo.
resize(NumElts);
3040 if (IntImm >= NumElts || IntImm < 0)
3042 if (!MatchInfo[IntImm])
3043 MatchInfo[IntImm] = TmpReg;
3047 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3049 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3058 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3065 auto GetUndef = [&]() {
3077 MI.eraseFromParent();
3081 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3083 std::tie(SubLHS, SubRHS) = MatchInfo;
3085 MI.eraseFromParent();
3096 unsigned LogicOpcode =
MI.getOpcode();
3097 assert(LogicOpcode == TargetOpcode::G_AND ||
3098 LogicOpcode == TargetOpcode::G_OR ||
3099 LogicOpcode == TargetOpcode::G_XOR);
3112 if (!LeftHandInst || !RightHandInst)
3114 unsigned HandOpcode = LeftHandInst->
getOpcode();
3115 if (HandOpcode != RightHandInst->
getOpcode())
3129 if (!XTy.
isValid() || XTy != YTy)
3134 switch (HandOpcode) {
3137 case TargetOpcode::G_ANYEXT:
3138 case TargetOpcode::G_SEXT:
3139 case TargetOpcode::G_ZEXT: {
3143 case TargetOpcode::G_TRUNC: {
3157 case TargetOpcode::G_AND:
3158 case TargetOpcode::G_ASHR:
3159 case TargetOpcode::G_LSHR:
3160 case TargetOpcode::G_SHL: {
3165 ExtraHandOpSrcReg = ZOp.
getReg();
3187 if (ExtraHandOpSrcReg.
isValid())
3199 "Expected at least one instr to build?");
3201 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3202 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3204 for (
auto &OperandFn : InstrToBuild.OperandFns)
3207 MI.eraseFromParent();
3211 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3212 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3213 int64_t ShlCst, AshrCst;
3219 if (ShlCst != AshrCst)
3222 {TargetOpcode::G_SEXT_INREG, {
MRI.
getType(Src)}}))
3224 MatchInfo = std::make_tuple(Src, ShlCst);
3229 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3230 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3233 std::tie(Src, ShiftAmt) = MatchInfo;
3236 MI.eraseFromParent();
3243 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3258 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3261 auto Zero =
B.buildConstant(Ty, 0);
3284 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3308 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3315 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3332 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3350 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3357 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3368 unsigned ExtBits =
MI.getOperand(2).getImm();
3374 int64_t Cst,
bool IsVector,
bool IsFP) {
3376 return (ScalarSizeBits == 1 && Cst == -1) ||
3399 unsigned NumOperands =
BuildMI->getNumSources();
3407 for (
I = 0;
I < NumOperands; ++
I) {
3412 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3415 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3418 auto UnmergeSrcMI =
MRI.
getVRegDef(SrcMI->getOperand(1).getReg());
3419 if (UnmergeMI != UnmergeSrcMI)
3430 for (;
I < NumOperands; ++
I) {
3434 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3439 MatchInfo = cast<GUnmerge>(UnmergeMI)->getSourceReg();
3449 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3452 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3470 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3475 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3483 MI.eraseFromParent();
3488 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3508 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3513 switch (Def->getOpcode()) {
3518 case TargetOpcode::G_ICMP:
3524 case TargetOpcode::G_FCMP:
3530 case TargetOpcode::G_AND:
3531 case TargetOpcode::G_OR:
3537 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3538 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3565 for (
Register Reg : RegsToNegate) {
3570 switch (Def->getOpcode()) {
3573 case TargetOpcode::G_ICMP:
3574 case TargetOpcode::G_FCMP: {
3581 case TargetOpcode::G_AND:
3584 case TargetOpcode::G_OR:
3592 MI.eraseFromParent();
3596 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3598 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3602 Register SharedReg =
MI.getOperand(2).getReg();
3623 return Y == SharedReg;
3627 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3630 std::tie(
X,
Y) = MatchInfo;
3634 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3635 MI.getOperand(2).setReg(
Y);
3640 auto &PtrAdd = cast<GPtrAdd>(
MI);
3641 Register DstReg = PtrAdd.getReg(0);
3650 return ConstVal && *ConstVal == 0;
3659 auto &PtrAdd = cast<GPtrAdd>(
MI);
3661 PtrAdd.eraseFromParent();
3668 Register Pow2Src1 =
MI.getOperand(2).getReg();
3675 MI.eraseFromParent();
3679 unsigned &SelectOpNo)
const {
3689 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3691 OtherOperandReg =
LHS;
3694 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3711 unsigned BinOpcode =
MI.getOpcode();
3716 bool CanFoldNonConst =
3717 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3722 if (CanFoldNonConst)
3744 unsigned BinOpcode =
MI.getOpcode();
3751 if (SelectOperand == 1) {
3765 MI.eraseFromParent();
3768std::optional<SmallVector<Register, 8>>
3769CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3770 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3799 const unsigned MaxIter =
3801 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3810 return std::nullopt;
3826 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
3827 return std::nullopt;
3839static std::optional<std::pair<GZExtLoad *, int64_t>>
3843 "Expected Reg to only have one non-debug use?");
3852 if (Shift % MemSizeInBits != 0)
3853 return std::nullopt;
3856 auto *Load = getOpcodeDef<GZExtLoad>(MaybeLoad,
MRI);
3858 return std::nullopt;
3860 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
3861 return std::nullopt;
3863 return std::make_pair(Load, Shift / MemSizeInBits);
3866std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
3867CombinerHelper::findLoadOffsetsForLoadOrCombine(
3870 const unsigned MemSizeInBits)
const {
3902 for (
auto Reg : RegsToVisit) {
3907 return std::nullopt;
3910 std::tie(Load, DstPos) = *LoadAndPos;
3918 return std::nullopt;
3921 auto &LoadMMO =
Load->getMMO();
3925 return std::nullopt;
3932 LoadPtr =
Load->getOperand(1).getReg();
3938 return std::nullopt;
3945 if (BasePtr != LoadPtr)
3946 return std::nullopt;
3948 if (
Idx < LowestIdx) {
3950 LowestIdxLoad =
Load;
3958 return std::nullopt;
3966 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
3967 EarliestLoad =
Load;
3968 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
3975 "Expected to find a load for each register?");
3976 assert(EarliestLoad != LatestLoad && EarliestLoad &&
3977 LatestLoad &&
"Expected at least two loads?");
3986 const unsigned MaxIter = 20;
3992 if (
MI.isLoadFoldBarrier())
3993 return std::nullopt;
3994 if (Iter++ == MaxIter)
3995 return std::nullopt;
3998 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4004 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4024 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4028 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4035 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4036 if (NarrowMemSizeInBits % 8 != 0)
4049 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4050 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4053 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4060 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4063 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4075 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4076 const unsigned ZeroByteOffset =
4080 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4081 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4082 ZeroOffsetIdx->second != LowestIdx)
4106 MIB.setInstrAndDebugLoc(*LatestLoad);
4108 MIB.buildLoad(LoadDst,
Ptr, *NewMMO);
4110 MIB.buildBSwap(Dst, LoadDst);
4117 auto &
PHI = cast<GPhi>(
MI);
4130 case TargetOpcode::G_ANYEXT:
4132 case TargetOpcode::G_ZEXT:
4133 case TargetOpcode::G_SEXT:
4147 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4150 case TargetOpcode::G_LOAD:
4151 case TargetOpcode::G_TRUNC:
4152 case TargetOpcode::G_SEXT:
4153 case TargetOpcode::G_ZEXT:
4154 case TargetOpcode::G_ANYEXT:
4155 case TargetOpcode::G_CONSTANT:
4159 if (InSrcs.
size() > 2)
4171 auto &
PHI = cast<GPhi>(
MI);
4180 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4181 auto SrcReg =
PHI.getIncomingValue(
I);
4183 if (!SrcMIs.
insert(SrcMI))
4189 if (InsertPt !=
MBB->
end() && InsertPt->isPHI())
4195 OldToNewSrcMap[SrcMI] = NewExt;
4204 NewPhi.
addMBB(MO.getMBB());
4208 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4216 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4228 unsigned VecIdx = Cst->Value.getZExtValue();
4233 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4237 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4238 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4258 if (ScalarTy != DstTy) {
4261 MI.eraseFromParent();
4269 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4270 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4293 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4298 unsigned Idx = Cst->getZExtValue();
4302 SrcDstPairs.emplace_back(
4303 std::make_pair(
MI.getOperand(
Idx + 1).getReg(), &
II));
4306 return ExtractedElts.
all();
4311 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4312 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4313 for (
auto &Pair : SrcDstPairs) {
4314 auto *ExtMI = Pair.second;
4316 ExtMI->eraseFromParent();
4318 MI.eraseFromParent();
4325 MI.eraseFromParent();
4336 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4342 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4343 unsigned FshOpc = 0;
4354 int64_t CstShlAmt, CstLShrAmt;
4357 CstShlAmt + CstLShrAmt ==
BitWidth) {
4358 FshOpc = TargetOpcode::G_FSHR;
4365 FshOpc = TargetOpcode::G_FSHL;
4371 FshOpc = TargetOpcode::G_FSHR;
4382 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4389 unsigned Opc =
MI.getOpcode();
4390 assert(Opc == TargetOpcode::G_FSHL || Opc == TargetOpcode::G_FSHR);
4395 unsigned RotateOpc =
4396 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4401 unsigned Opc =
MI.getOpcode();
4402 assert(Opc == TargetOpcode::G_FSHL || Opc == TargetOpcode::G_FSHR);
4403 bool IsFSHL = Opc == TargetOpcode::G_FSHL;
4406 : TargetOpcode::G_ROTR));
4407 MI.removeOperand(2);
4413 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4414 MI.getOpcode() == TargetOpcode::G_ROTR);
4418 bool OutOfRange =
false;
4419 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4420 if (
auto *CI = dyn_cast<ConstantInt>(
C))
4421 OutOfRange |= CI->getValue().uge(Bitsize);
4428 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4429 MI.getOpcode() == TargetOpcode::G_ROTR);
4437 MI.getOperand(2).setReg(Amt);
4442 int64_t &MatchInfo)
const {
4443 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4455 if (KnownRHS.isUnknown())
4458 std::optional<bool> KnownVal;
4459 if (KnownRHS.isZero()) {
4488 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4513 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4519 unsigned Op = TargetOpcode::COPY;
4520 if (DstSize != LHSSize)
4521 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4532 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4542 int64_t AndMaskBits;
4550 if (AndMaskBits & OrMaskBits)
4556 if (
MI.getOperand(1).getReg() == AndMaskReg)
4557 MI.getOperand(2).setReg(AndMaskReg);
4558 MI.getOperand(1).setReg(Src);
4568 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4575 int64_t Width =
MI.getOperand(2).getImm();
4587 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4588 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4589 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4606 int64_t AndImm, LSBImm;
4615 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4616 if (MaybeMask & (MaybeMask + 1))
4625 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4626 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4627 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4635 const unsigned Opcode =
MI.getOpcode();
4636 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4638 const Register Dst =
MI.getOperand(0).getReg();
4640 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4641 ? TargetOpcode::G_SBFX
4642 : TargetOpcode::G_UBFX;
4663 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4667 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4671 const int64_t Pos = ShrAmt - ShlAmt;
4672 const int64_t Width =
Size - ShrAmt;
4675 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4676 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4677 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4685 const unsigned Opcode =
MI.getOpcode();
4686 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4688 const Register Dst =
MI.getOperand(0).getReg();
4705 if (ShrAmt < 0 || ShrAmt >=
Size)
4709 if (0 == (SMask >> ShrAmt)) {
4711 B.buildConstant(Dst, 0);
4718 UMask |= maskTrailingOnes<uint64_t>(ShrAmt);
4719 UMask &= maskTrailingOnes<uint64_t>(
Size);
4724 const int64_t Pos = ShrAmt;
4729 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4733 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4734 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4735 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4740bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4742 auto &PtrAdd = cast<GPtrAdd>(
MI);
4744 Register Src1Reg = PtrAdd.getBaseReg();
4745 auto *Src1Def = getOpcodeDef<GPtrAdd>(Src1Reg,
MRI);
4749 Register Src2Reg = PtrAdd.getOffsetReg();
4761 const APInt &C1APIntVal = *C1;
4762 const APInt &C2APIntVal = *C2;
4763 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4769 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4770 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4771 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4778 auto *LdStMI = dyn_cast<GLoadStore>(ConvUseMI);
4789 PtrAdd.getMF()->getFunction().getContext());
4790 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4791 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4797 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4809 Register Src1Reg =
MI.getOperand(1).getReg();
4810 if (
RHS->getOpcode() != TargetOpcode::G_ADD)
4822 MI.getOperand(1).setReg(NewBase.getReg(0));
4823 MI.getOperand(2).setReg(
RHS->getOperand(2).getReg());
4826 return !reassociationCanBreakAddressingModePattern(
MI);
4836 std::optional<ValueAndVReg> LHSCstOff;
4841 auto *LHSPtrAdd = cast<GPtrAdd>(
LHS);
4846 LHSPtrAdd->moveBefore(&
MI);
4849 auto NewCst =
B.buildConstant(
MRI.
getType(RHSReg), LHSCstOff->Value);
4851 MI.getOperand(2).setReg(NewCst.getReg(0));
4854 LHSPtrAdd->getOperand(2).setReg(RHSReg);
4857 return !reassociationCanBreakAddressingModePattern(
MI);
4864 auto *LHSPtrAdd = dyn_cast<GPtrAdd>(
LHS);
4868 Register Src2Reg =
MI.getOperand(2).getReg();
4869 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
4870 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
4879 auto NewCst =
B.buildConstant(
MRI.
getType(Src2Reg), *C1 + *C2);
4881 MI.getOperand(1).setReg(LHSSrc1);
4882 MI.getOperand(2).setReg(NewCst.getReg(0));
4885 return !reassociationCanBreakAddressingModePattern(
MI);
4890 auto &PtrAdd = cast<GPtrAdd>(
MI);
4942 auto NewCst =
B.buildInstr(Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
4943 B.buildInstr(Opc, {DstReg}, {OpLHSLHS, NewCst});
4951 auto NewLHSLHS =
B.buildInstr(Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
4952 B.buildInstr(Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
4965 unsigned Opc =
MI.getOpcode();
4978 APInt &MatchInfo)
const {
4983 MatchInfo = *MaybeCst;
4991 APInt &MatchInfo)
const {
4997 MatchInfo = *MaybeCst;
5009 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5015 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5016 MI.getOpcode() == TargetOpcode::G_FMAD);
5017 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5034 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5057 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5081 case TargetOpcode::G_ADD:
5082 case TargetOpcode::G_SUB:
5083 case TargetOpcode::G_MUL:
5084 case TargetOpcode::G_AND:
5085 case TargetOpcode::G_OR:
5086 case TargetOpcode::G_XOR:
5094 auto Mask = Cst->Value;
5099 unsigned NarrowWidth = Mask.countr_one();
5105 auto &MF = *
MI.getMF();
5108 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5109 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5123 MI.getOperand(1).setReg(Ext.getReg(0));
5131 unsigned Opc =
MI.getOpcode();
5132 assert(Opc == TargetOpcode::G_UMULO || Opc == TargetOpcode::G_SMULO);
5139 unsigned NewOpc = Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5140 : TargetOpcode::G_SADDO;
5142 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5151 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5152 MI.getOpcode() == TargetOpcode::G_SMULO);
5161 B.buildConstant(Dst, 0);
5162 B.buildConstant(Carry, 0);
5171 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5172 MI.getOpcode() == TargetOpcode::G_SADDE ||
5173 MI.getOpcode() == TargetOpcode::G_USUBE ||
5174 MI.getOpcode() == TargetOpcode::G_SSUBE);
5179 switch (
MI.getOpcode()) {
5180 case TargetOpcode::G_UADDE:
5181 NewOpcode = TargetOpcode::G_UADDO;
5183 case TargetOpcode::G_SADDE:
5184 NewOpcode = TargetOpcode::G_SADDO;
5186 case TargetOpcode::G_USUBE:
5187 NewOpcode = TargetOpcode::G_USUBO;
5189 case TargetOpcode::G_SSUBE:
5190 NewOpcode = TargetOpcode::G_SSUBO;
5194 MI.setDesc(
B.getTII().get(NewOpcode));
5195 MI.removeOperand(4);
5203 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5237 B.buildSub(Dst, Zero, ReplaceReg);
5246 assert(
MI.getOpcode() == TargetOpcode::G_UDIV);
5247 auto &UDiv = cast<GenericMachineInstr>(
MI);
5259 bool UseSRL =
false;
5264 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5266 if (IsSplat && !Factors.
empty()) {
5272 auto *CI = cast<ConstantInt>(
C);
5273 APInt Divisor = CI->getValue();
5282 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5283 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5294 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5295 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5298 Factor = Factors[0];
5306 return MIB.buildMul(Ty, Res, Factor);
5309 unsigned KnownLeadingZeros =
5312 bool UseNPQ =
false;
5314 auto BuildUDIVPattern = [&](
const Constant *
C) {
5315 auto *CI = cast<ConstantInt>(
C);
5316 const APInt &Divisor = CI->getValue();
5318 bool SelNPQ =
false;
5320 unsigned PreShift = 0, PostShift = 0;
5325 if (!Divisor.
isOne()) {
5331 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5333 Magic = std::move(magics.
Magic);
5336 "We shouldn't generate an undefined shift!");
5338 "We shouldn't generate an undefined shift!");
5342 SelNPQ = magics.
IsAdd;
5346 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5347 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5349 MIB.buildConstant(ScalarTy,
5354 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5362 assert(Matched &&
"Expected unary predicate match to succeed");
5364 Register PreShift, PostShift, MagicFactor, NPQFactor;
5365 auto *RHSDef = getOpcodeDef<GBuildVector>(
RHS,
MRI);
5367 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5368 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5369 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5370 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5373 "Non-build_vector operation should have been a scalar");
5374 PreShift = PreShifts[0];
5375 MagicFactor = MagicFactors[0];
5376 PostShift = PostShifts[0];
5380 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5383 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5386 Register NPQ = MIB.buildSub(Ty,
LHS, Q).getReg(0);
5391 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5393 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5395 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5398 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5399 auto One = MIB.buildConstant(Ty, 1);
5400 auto IsOne = MIB.buildICmp(
5403 return MIB.buildSelect(Ty, IsOne,
LHS, Q);
5407 assert(
MI.getOpcode() == TargetOpcode::G_UDIV);
5412 auto &MF = *
MI.getMF();
5421 if (MF.getFunction().hasMinSize())
5440 {TargetOpcode::G_ICMP,
5456 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5461 auto &MF = *
MI.getMF();
5470 if (MF.getFunction().hasMinSize())
5489 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5490 auto &SDiv = cast<GenericMachineInstr>(
MI);
5500 bool UseSRA =
false;
5506 auto BuildSDIVPattern = [&](
const Constant *
C) {
5508 if (IsSplat && !Factors.
empty()) {
5514 auto *CI = cast<ConstantInt>(
C);
5515 APInt Divisor = CI->getValue();
5525 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5526 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5533 assert(Matched &&
"Expected unary predicate match to succeed");
5537 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5538 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5541 Factor = Factors[0];
5549 return MIB.buildMul(Ty, Res, Factor);
5553 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5554 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5555 "Expected SDIV or UDIV");
5556 auto &Div = cast<GenericMachineInstr>(
MI);
5558 auto MatchPow2 = [&](
const Constant *
C) {
5559 auto *CI = dyn_cast<ConstantInt>(
C);
5560 return CI && (CI->getValue().isPowerOf2() ||
5561 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5567 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5568 auto &SDiv = cast<GenericMachineInstr>(
MI);
5622 MI.eraseFromParent();
5626 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5627 auto &UDiv = cast<GenericMachineInstr>(
MI);
5636 MI.eraseFromParent();
5640 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
5645 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
5646 if (
auto *CI = dyn_cast<ConstantInt>(
C))
5647 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
5668 MI.eraseFromParent();
5673 unsigned Opc =
MI.getOpcode();
5674 assert(Opc == TargetOpcode::G_FADD || Opc == TargetOpcode::G_FSUB ||
5675 Opc == TargetOpcode::G_FMUL || Opc == TargetOpcode::G_FDIV ||
5676 Opc == TargetOpcode::G_FMAD || Opc == TargetOpcode::G_FMA);
5688 Opc = TargetOpcode::G_FSUB;
5693 Opc = TargetOpcode::G_FADD;
5699 else if ((Opc == TargetOpcode::G_FMUL || Opc == TargetOpcode::G_FDIV ||
5700 Opc == TargetOpcode::G_FMAD || Opc == TargetOpcode::G_FMA) &&
5709 MI.setDesc(
B.getTII().get(Opc));
5710 MI.getOperand(1).setReg(
X);
5711 MI.getOperand(2).setReg(
Y);
5719 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
5722 MatchInfo =
MI.getOperand(2).getReg();
5732 if (LHSCst->Value.isNegZero())
5736 if (LHSCst->Value.isPosZero())
5753 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
5761 MRI.use_instr_nodbg_end()) >
5763 MRI.use_instr_nodbg_end());
5767 bool &AllowFusionGlobally,
5769 bool CanReassociate)
const {
5771 auto *MF =
MI.getMF();
5772 const auto &TLI = *MF->getSubtarget().getTargetLowering();
5776 if (CanReassociate &&
5783 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
5786 if (!HasFMAD && !HasFMA)
5790 Options.UnsafeFPMath || HasFMAD;
5795 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
5802 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5804 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5812 unsigned PreferredFusedOpcode =
5813 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5827 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5828 {
LHS.MI->getOperand(1).getReg(),
5829 LHS.MI->getOperand(2).getReg(),
RHS.Reg});
5838 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5839 {
RHS.MI->getOperand(1).getReg(),
5840 RHS.MI->getOperand(2).getReg(),
LHS.Reg});
5851 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5853 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5857 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
5864 unsigned PreferredFusedOpcode =
5865 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5879 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5884 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5885 {FpExtX.getReg(0), FpExtY.getReg(0),
RHS.Reg});
5894 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5899 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5900 {FpExtX.getReg(0), FpExtY.getReg(0),
LHS.Reg});
5911 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5913 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5923 unsigned PreferredFusedOpcode =
5924 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5937 if (
LHS.MI->getOpcode() == PreferredFusedOpcode &&
5939 TargetOpcode::G_FMUL) &&
5946 else if (
RHS.MI->getOpcode() == PreferredFusedOpcode &&
5948 TargetOpcode::G_FMUL) &&
5957 Register X = FMA->getOperand(1).getReg();
5958 Register Y = FMA->getOperand(2).getReg();
5964 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
5965 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5977 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5979 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5986 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
5993 unsigned PreferredFusedOpcode =
5994 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6007 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6008 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6010 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6012 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6019 if (
LHS.MI->getOpcode() == PreferredFusedOpcode &&
6023 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6028 LHS.MI->getOperand(1).getReg(),
6029 LHS.MI->getOperand(2).getReg(),
B);
6040 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6043 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6048 X =
B.buildFPExt(DstType,
X).getReg(0);
6049 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6060 if (
RHS.MI->getOpcode() == PreferredFusedOpcode &&
6064 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6069 RHS.MI->getOperand(1).getReg(),
6070 RHS.MI->getOperand(2).getReg(),
B);
6081 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6084 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6089 X =
B.buildFPExt(DstType,
X).getReg(0);
6090 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6104 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6106 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6118 int FirstMulHasFewerUses =
true;
6122 FirstMulHasFewerUses =
false;
6124 unsigned PreferredFusedOpcode =
6125 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6128 if (FirstMulHasFewerUses &&
6133 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6134 {
LHS.MI->getOperand(1).getReg(),
6135 LHS.MI->getOperand(2).getReg(), NegZ});
6144 B.buildFNeg(DstTy,
RHS.MI->getOperand(1).getReg()).
getReg(0);
6145 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6146 {NegY,
RHS.MI->getOperand(2).getReg(),
LHS.Reg});
6157 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6159 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6167 unsigned PreferredFusedOpcode =
6168 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6179 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6180 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6192 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6205 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6207 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6215 unsigned PreferredFusedOpcode =
6216 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6228 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6229 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6230 {FpExtX, FpExtY, NegZ});
6242 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6245 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6246 {NegY, FpExtZ, LHSReg});
6257 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6259 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6263 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6268 unsigned PreferredFusedOpcode =
6269 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6273 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6274 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6275 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6286 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6292 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6302 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6315 unsigned &IdxToPropagate)
const {
6317 switch (
MI.getOpcode()) {
6320 case TargetOpcode::G_FMINNUM:
6321 case TargetOpcode::G_FMAXNUM:
6322 PropagateNaN =
false;
6324 case TargetOpcode::G_FMINIMUM:
6325 case TargetOpcode::G_FMAXIMUM:
6326 PropagateNaN =
true;
6330 auto MatchNaN = [&](
unsigned Idx) {
6335 IdxToPropagate = PropagateNaN ?
Idx : (
Idx == 1 ? 2 : 1);
6339 return MatchNaN(1) || MatchNaN(2);
6343 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6353 Reg == MaybeSameReg;
6388 std::optional<ValueAndVReg> ShiftAmount;
6419 std::optional<ValueAndVReg> ShiftAmt;
6426 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
6430unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6432 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6433 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6434 "Expected a NaN behaviour?");
6444 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6445 return TargetOpcode::G_FMAXNUM;
6446 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6447 return TargetOpcode::G_FMAXIMUM;
6448 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6449 return TargetOpcode::G_FMAXNUM;
6450 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6451 return TargetOpcode::G_FMAXIMUM;
6457 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6458 return TargetOpcode::G_FMINNUM;
6459 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6460 return TargetOpcode::G_FMINIMUM;
6461 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6462 return TargetOpcode::G_FMINNUM;
6463 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6465 return TargetOpcode::G_FMINIMUM;
6469CombinerHelper::SelectPatternNaNBehaviour
6471 bool IsOrderedComparison)
const {
6475 if (!LHSSafe && !RHSSafe)
6476 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
6477 if (LHSSafe && RHSSafe)
6478 return SelectPatternNaNBehaviour::RETURNS_ANY;
6481 if (IsOrderedComparison)
6482 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
6483 : SelectPatternNaNBehaviour::RETURNS_OTHER;
6486 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
6487 : SelectPatternNaNBehaviour::RETURNS_NAN;
6509 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
6511 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
6513 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
6516 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
6517 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
6518 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
6519 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
6521 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
6524 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
6525 if (!Opc || !
isLegal({Opc, {DstTy}}))
6529 if (Opc != TargetOpcode::G_FMAXIMUM && Opc != TargetOpcode::G_FMINIMUM) {
6534 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
6536 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
6541 B.buildInstr(Opc, {Dst}, {CmpLHS, CmpRHS});
6549 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
6556 Register TrueVal =
MI.getOperand(2).getReg();
6557 Register FalseVal =
MI.getOperand(3).getReg();
6558 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
6563 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
6576 if (MatchedSub &&
X != OpLHS)
6584 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
6588 B.buildICmp(Pred, Dst,
Y, Zero);
6594 Register ShiftReg =
MI.getOperand(2).getReg();
6596 auto IsShiftTooBig = [&](
const Constant *
C) {
6597 auto *CI = dyn_cast<ConstantInt>(
C);
6604 unsigned LHSOpndIdx = 1;
6605 unsigned RHSOpndIdx = 2;
6606 switch (
MI.getOpcode()) {
6607 case TargetOpcode::G_UADDO:
6608 case TargetOpcode::G_SADDO:
6609 case TargetOpcode::G_UMULO:
6610 case TargetOpcode::G_SMULO:
6624 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
6629 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
6636 std::optional<FPValueAndVReg> ValAndVReg;
6644 unsigned LHSOpndIdx = 1;
6645 unsigned RHSOpndIdx = 2;
6646 switch (
MI.getOpcode()) {
6647 case TargetOpcode::G_UADDO:
6648 case TargetOpcode::G_SADDO:
6649 case TargetOpcode::G_UMULO:
6650 case TargetOpcode::G_SMULO:
6657 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
6658 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
6659 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
6660 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
6664bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
6667 return isConstantSplatVector(Src, 1, AllowUndefs);
6669 if (AllowUndefs && getOpcodeDef<GImplicitDef>(Src,
MRI) !=
nullptr)
6672 return IConstant && IConstant->Value == 1;
6677bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
6680 return isConstantSplatVector(Src, 0, AllowUndefs);
6682 if (AllowUndefs && getOpcodeDef<GImplicitDef>(Src,
MRI) !=
nullptr)
6685 return IConstant && IConstant->Value == 0;
6692bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
6693 bool AllowUndefs)
const {
6699 for (
unsigned I = 0;
I < NumSources; ++
I) {
6702 if (ImplicitDef && AllowUndefs)
6704 if (ImplicitDef && !AllowUndefs)
6706 std::optional<ValueAndVReg> IConstant =
6708 if (IConstant && IConstant->Value == SplatValue)
6718CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
6721 return IConstant->Value;
6725 return std::nullopt;
6728 std::optional<APInt>
Value = std::nullopt;
6729 for (
unsigned I = 0;
I < NumSources; ++
I) {
6730 std::optional<ValueAndVReg> IConstant =
6733 return std::nullopt;
6737 return std::nullopt;
6743bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
6753 for (
unsigned I = 0;
I < NumSources; ++
I) {
6754 std::optional<ValueAndVReg> IConstant =
6763bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
6781 std::optional<ValueAndVReg> TrueOpt =
6783 std::optional<ValueAndVReg> FalseOpt =
6786 if (!TrueOpt || !FalseOpt)
6789 APInt TrueValue = TrueOpt->Value;
6790 APInt FalseValue = FalseOpt->Value;
6795 B.setInstrAndDebugLoc(*
Select);
6796 B.buildZExtOrTrunc(Dest,
Cond);
6804 B.setInstrAndDebugLoc(*
Select);
6805 B.buildSExtOrTrunc(Dest,
Cond);
6813 B.setInstrAndDebugLoc(*
Select);
6815 B.buildNot(Inner,
Cond);
6816 B.buildZExtOrTrunc(Dest, Inner);
6824 B.setInstrAndDebugLoc(*
Select);
6826 B.buildNot(Inner,
Cond);
6827 B.buildSExtOrTrunc(Dest, Inner);
6833 if (TrueValue - 1 == FalseValue) {
6835 B.setInstrAndDebugLoc(*
Select);
6837 B.buildZExtOrTrunc(Inner,
Cond);
6838 B.buildAdd(Dest, Inner, False);
6844 if (TrueValue + 1 == FalseValue) {
6846 B.setInstrAndDebugLoc(*
Select);
6848 B.buildSExtOrTrunc(Inner,
Cond);
6849 B.buildAdd(Dest, Inner, False);
6857 B.setInstrAndDebugLoc(*
Select);
6859 B.buildZExtOrTrunc(Inner,
Cond);
6862 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
6863 B.buildShl(Dest, Inner, ShAmtC, Flags);
6870 B.setInstrAndDebugLoc(*
Select);
6872 B.buildSExtOrTrunc(Inner,
Cond);
6873 B.buildOr(Dest, Inner, False, Flags);
6881 B.setInstrAndDebugLoc(*
Select);
6883 B.buildNot(Not,
Cond);
6885 B.buildSExtOrTrunc(Inner, Not);
6886 B.buildOr(Dest, Inner, True, Flags);
6895bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
6912 if (CondTy != TrueTy)
6917 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
6919 B.setInstrAndDebugLoc(*
Select);
6921 B.buildZExtOrTrunc(Ext,
Cond);
6922 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
6923 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
6930 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
6932 B.setInstrAndDebugLoc(*
Select);
6934 B.buildZExtOrTrunc(Ext,
Cond);
6935 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
6936 B.buildAnd(DstReg, Ext, FreezeTrue);
6942 if (isOneOrOneSplat(False,
true)) {
6944 B.setInstrAndDebugLoc(*
Select);
6947 B.buildNot(Inner,
Cond);
6950 B.buildZExtOrTrunc(Ext, Inner);
6951 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
6952 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
6958 if (isZeroOrZeroSplat(True,
true)) {
6960 B.setInstrAndDebugLoc(*
Select);
6963 B.buildNot(Inner,
Cond);
6966 B.buildZExtOrTrunc(Ext, Inner);
6967 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
6968 B.buildAnd(DstReg, Ext, FreezeFalse);
6999 Register CmpLHS = Cmp->getLHSReg();
7000 Register CmpRHS = Cmp->getRHSReg();
7003 if (True == CmpRHS && False == CmpLHS) {
7011 if (True != CmpLHS || False != CmpRHS)
7051 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7054 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7064bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7066 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7067 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7071 unsigned Flags = Logic->
getFlags();
7074 GICmp *Cmp1 = getOpcodeDef<GICmp>(LHS,
MRI);
7079 GICmp *Cmp2 = getOpcodeDef<GICmp>(RHS,
MRI);
7090 std::optional<ValueAndVReg> MaybeC1 =
7094 C1 = MaybeC1->Value;
7096 std::optional<ValueAndVReg> MaybeC2 =
7100 C2 = MaybeC2->Value;
7121 std::optional<APInt> Offset1;
7122 std::optional<APInt> Offset2;
7124 if (
GAdd *
Add = getOpcodeDef<GAdd>(R1,
MRI)) {
7125 std::optional<ValueAndVReg> MaybeOffset1 =
7128 R1 =
Add->getLHSReg();
7129 Offset1 = MaybeOffset1->Value;
7133 std::optional<ValueAndVReg> MaybeOffset2 =
7136 R2 =
Add->getLHSReg();
7137 Offset2 = MaybeOffset2->Value;
7156 bool CreateMask =
false;
7169 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7182 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7192 if (CreateMask &&
Offset != 0) {
7193 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7194 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7195 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7196 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7197 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7198 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7199 B.buildZExtOrTrunc(DstReg, ICmp);
7200 }
else if (CreateMask &&
Offset == 0) {
7201 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7202 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7203 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7204 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7205 B.buildZExtOrTrunc(DstReg, ICmp);
7206 }
else if (!CreateMask &&
Offset != 0) {
7207 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7208 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7209 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7210 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7211 B.buildZExtOrTrunc(DstReg, ICmp);
7212 }
else if (!CreateMask &&
Offset == 0) {
7213 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7214 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7215 B.buildZExtOrTrunc(DstReg, ICmp);
7223bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7229 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7232 GFCmp *Cmp1 = getOpcodeDef<GFCmp>(LHS,
MRI);
7237 GFCmp *Cmp2 = getOpcodeDef<GFCmp>(RHS,
MRI);
7247 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7261 if (LHS0 == RHS1 && LHS1 == RHS0) {
7267 if (LHS0 == RHS0 && LHS1 == RHS1) {
7271 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7278 auto False =
B.buildConstant(CmpTy, 0);
7279 B.buildZExtOrTrunc(DestReg, False);
7286 B.buildZExtOrTrunc(DestReg, True);
7288 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7289 B.buildZExtOrTrunc(DestReg, Cmp);
7301 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7304 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7313 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7316 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7331 bool IsSigned =
Add->isSigned();
7340 B.buildUndef(Carry);
7346 if (isConstantOrConstantVectorI(
LHS) && !isConstantOrConstantVectorI(
RHS)) {
7349 B.buildSAddo(Dst, Carry,
RHS,
LHS);
7355 B.buildUAddo(Dst, Carry,
RHS,
LHS);
7360 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(
LHS);
7361 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(
RHS);
7367 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7368 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7370 B.buildConstant(Dst, Result);
7371 B.buildConstant(Carry, Overflow);
7379 B.buildCopy(Dst,
LHS);
7380 B.buildConstant(Carry, 0);
7392 std::optional<APInt> MaybeAddRHS =
7393 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
7396 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
7397 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
7401 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7402 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7408 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7409 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7434 B.buildConstant(Carry, 0);
7442 B.buildConstant(Carry, 1);
7457 B.buildConstant(Carry, 0);
7473 B.buildConstant(Carry, 0);
7481 B.buildConstant(Carry, 1);
7499 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
7505 auto [Dst,
Base] =
MI.getFirst2Regs();
7511 MI.removeFromParent();
7523 std::optional<SrcOp> Res;
7525 while (ExpVal > 0) {
7544 MI.eraseFromParent();
7550 const GSub *Sub = cast<GSub>(&
MI);
7563 auto Const =
B.buildConstant(DstTy, C1 - C2);
7564 B.buildAdd(Dst,
Add->getLHSReg(), Const);
7573 const GSub *Sub = cast<GSub>(&
MI);
7586 auto Const =
B.buildConstant(DstTy, C2 - C1);
7587 B.buildSub(Dst, Const,
Add->getLHSReg());
7596 const GSub *Sub1 = cast<GSub>(&
MI);
7609 auto Const =
B.buildConstant(DstTy, C1 + C2);
7619 const GSub *Sub1 = cast<GSub>(&
MI);
7632 auto Const =
B.buildConstant(DstTy, C1 - C2);
7655 auto Const =
B.buildConstant(DstTy, C2 - C1);
7664 const GUnmerge *Unmerge = cast<GUnmerge>(&
MI);
7694 const GAnyExt *
Any = dyn_cast<GAnyExt>(Source);
7700 if (
const GBuildVector *BV = dyn_cast<GBuildVector>(NextSource)) {
7707 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
7711 LLT SmallBvTy = DstTy;
7715 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
7720 {TargetOpcode::G_ANYEXT,
7732 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
7747 bool Changed =
false;
7748 auto &Shuffle = cast<GShuffleVector>(
MI);
7753 const unsigned NumDstElts = OrigMask.
size();
7754 for (
unsigned i = 0; i != NumDstElts; ++i) {
7755 int Idx = OrigMask[i];
7756 if (
Idx >= (
int)NumSrcElems) {
7767 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
7768 std::move(NewMask));
7775 const unsigned MaskSize = Mask.size();
7776 for (
unsigned I = 0;
I < MaskSize; ++
I) {
7781 if (
Idx < (
int)NumElems)
7782 Mask[
I] =
Idx + NumElems;
7784 Mask[
I] =
Idx - NumElems;
7791 auto &Shuffle = cast<GShuffleVector>(
MI);
7794 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
7797 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
7803 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
7809 bool TouchesSrc1 =
false;
7810 bool TouchesSrc2 =
false;
7811 const unsigned NumElems = Mask.size();
7812 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
7816 if (Mask[
Idx] < (
int)NumSrcElems)
7822 if (TouchesSrc1 == TouchesSrc2)
7825 Register NewSrc1 = Shuffle.getSrc1Reg();
7828 NewSrc1 = Shuffle.getSrc2Reg();
7833 auto Undef =
B.buildUndef(Src1Ty);
7834 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1, Undef, NewMask);
7871 B.buildConstant(Carry, 0);
7896 B.buildConstant(Carry, 0);
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
AMDGPU Register Bank Select
This file declares a class to represent arbitrary precision floating point values and provide a varie...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool hasMoreUses(const MachineInstr &MI0, const MachineInstr &MI1, const MachineRegisterInfo &MRI)
static bool isContractableFMul(MachineInstr &MI, bool AllowFusionGlobally)
Checks if MI is TargetOpcode::G_FMUL and contractable either due to global flags or MachineInstr flag...
static unsigned getIndexedOpc(unsigned LdStOpc)
static APFloat constantFoldFpUnary(const MachineInstr &MI, const MachineRegisterInfo &MRI, const APFloat &Val)
static std::optional< std::pair< GZExtLoad *, int64_t > > matchLoadAndBytePosition(Register Reg, unsigned MemSizeInBits, const MachineRegisterInfo &MRI)
Helper function for findLoadOffsetsForLoadOrCombine.
static Register peekThroughBitcast(Register Reg, const MachineRegisterInfo &MRI)
static unsigned bigEndianByteAt(const unsigned ByteWidth, const unsigned I)
static cl::opt< bool > ForceLegalIndexing("force-legal-indexing", cl::Hidden, cl::init(false), cl::desc("Force all indexed operations to be " "legal for the GlobalISel combiner"))
static void commuteMask(MutableArrayRef< int > Mask, const unsigned NumElems)
static cl::opt< unsigned > PostIndexUseThreshold("post-index-use-threshold", cl::Hidden, cl::init(32), cl::desc("Number of uses of a base pointer to check before it is no longer " "considered for post-indexing."))
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
static unsigned getExtLoadOpcForExtend(unsigned ExtOpc)
static bool isConstValidTrue(const TargetLowering &TLI, unsigned ScalarSizeBits, int64_t Cst, bool IsVector, bool IsFP)
static LLT getMidVTForTruncRightShiftCombine(LLT ShiftTy, LLT TruncTy)
static bool canFoldInAddressingMode(GLoadStore *MI, const TargetLowering &TLI, MachineRegisterInfo &MRI)
Return true if 'MI' is a load or a store that may be fold it's address operand into the load / store ...
static unsigned littleEndianByteAt(const unsigned ByteWidth, const unsigned I)
static Register buildLogBase2(Register V, MachineIRBuilder &MIB)
Determines the LogBase2 value for a non-null input value using the transform: LogBase2(V) = (EltBits ...
This contains common combine transformations that may be used in a combine pass,or by the target else...
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")
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
Remove Loads Into Fake Uses
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.
void lshrInPlace(unsigned ShiftAmt)
Logical right-shift this APInt by ShiftAmt in place.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
unsigned countr_one() const
Count the number of trailing one bits.
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
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 applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCommuteShift(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match expression trees of the form.
const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
void applyPtrAddZero(MachineInstr &MI) const
bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2) const
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
bool matchUnmergeValuesAnyExtBuildVector(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchSelectSameVal(MachineInstr &MI) const
Optimize (cond ? x : x) -> x.
bool matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*ADDE x, y, 0) -> (G_*ADDO x, y) (G_*SUBE x, y, 0) -> (G_*SUBO x, y)
bool matchShuffleToExtract(MachineInstr &MI) const
bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applySimplifyURemByPow2(MachineInstr &MI) const
Combine G_UREM x, (known power of 2) to an add and bitmasking.
bool matchCombineUnmergeZExtToZExt(MachineInstr &MI) const
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
bool matchPtrAddZero(MachineInstr &MI) const
}
void applyCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false) const
bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
bool matchSDivByConst(MachineInstr &MI) const
bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
void applyCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement) const
Delete MI and replace all of its uses with Replacement.
bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, Register ToReg) const
Replace a single register operand with a new register and inform the observer of the changes.
bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate commutative binary operations like G_ADD.
void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCommuteConstantToRHS(MachineInstr &MI) const
Match constant LHS ops that should be commuted.
const DataLayout & getDataLayout() const
bool matchBinOpSameVal(MachineInstr &MI) const
Optimize (x op x) -> x.
bool matchCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
Try to combine G_[SU]DIV and G_[SU]REM into a single G_[SU]DIVREM when their source operands are iden...
void applyUMulHToLShr(MachineInstr &MI) const
void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
Fold (shift (shift base, x), y) -> (shift base (x+y))
void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
bool matchAllExplicitUsesAreUndef(MachineInstr &MI) const
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
bool matchOrShiftToFunnelShift(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI precedes UseMI or they are the same instruction.
bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
const TargetLowering & getTargetLowering() const
bool matchShuffleUndefRHS(MachineInstr &MI, BuildFnTy &MatchInfo) const
Remove references to rhs if it is undef.
void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Replace MI with a series of instructions described in MatchInfo.
void applySDivByPow2(MachineInstr &MI) const
void applySimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
void applyUDivByPow2(MachineInstr &MI) const
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ors.
void applySDivByConst(MachineInstr &MI) const
bool matchSimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
Return true if MI is a G_ADD which can be simplified to a G_SUB.
void replaceInstWithConstant(MachineInstr &MI, int64_t C) const
Replace an instruction with a G_CONSTANT with value C.
bool tryEmitMemcpyInline(MachineInstr &MI) const
Emit loads and stores that perform the given memcpy.
bool matchCombineFSubFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), (fneg z)) (fsub (fpext (fmul x,...
void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx) const
Checks if constant at ConstIdx is larger than MI 's bitwidth.
void applyCombineCopy(MachineInstr &MI) const
bool matchAddSubSameReg(MachineInstr &MI, Register &Src) const
Transform G_ADD(x, G_SUB(y, x)) to y.
bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
void applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
bool matchUDivByConst(MachineInstr &MI) const
Combine G_UDIV by constant into a multiply by magic constant.
bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
bool matchCombineFAddFMAFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y, (fma u, v, z)) (fadd (fmad x,...
bool matchSextTruncSextLoad(MachineInstr &MI) const
bool matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo) const
Fold away a merge of an unmerge of the corresponding values.
bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchDivByPow2(MachineInstr &MI, bool IsSigned) const
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd x, fneg(y)) -> (fsub x, y) (fadd fneg(x), y) -> (fsub y, x) (fsub x,...
bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match (and (load x), mask) -> zextload x.
bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
bool matchCombineCopy(MachineInstr &MI) const
bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
Fold (xor (and x, y), y) -> (and (not x), y) {.
bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops) const
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) Transform G_ADD y,...
bool matchShiftsTooBig(MachineInstr &MI) const
Match shifts greater or equal to the bitwidth of the operation.
void replaceInstWithFConstant(MachineInstr &MI, double C) const
Replace an instruction with a G_FCONSTANT with value C.
bool matchFunnelShiftToRotate(MachineInstr &MI) const
Match an FSHL or FSHR that can be combined to a ROTR or ROTL rotate.
bool matchRedundantSExtInReg(MachineInstr &MI) const
void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
void applyFunnelShiftConstantModulo(MachineInstr &MI) const
Replaces the shift amount in MI with ShiftAmt % BW.
bool matchOperandIsZero(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is zero.
bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData) const
void applyUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
bool matchShuffleDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Turn shuffle a, b, mask -> shuffle undef, b, mask iff mask does not reference a.
bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
Transform a multiply by a power-of-2 value to a left shift.
bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo) const
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo) const
SelectOperand is the operand in binary operator MI that is the select to fold.
bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_UMULO x, 2) -> (G_UADDO x, x) (G_SMULO x, 2) -> (G_SADDO x, x)
bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
bool tryCombineCopy(MachineInstr &MI) const
If MI is COPY, try to combine it.
bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
bool isPreLegalize() const
void applyCombineShuffleVector(MachineInstr &MI, const ArrayRef< Register > Ops) const
Replace MI with a concat_vectors with Ops.
bool matchUndefShuffleVectorMask(MachineInstr &MI) const
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
bool matchAnyExplicitUseIsUndef(MachineInstr &MI) const
Return true if any explicit use operand on MI is defined by a G_IMPLICIT_DEF.
bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
bool matchCombineSubToAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
If we have a shift-by-constant of a bitwise logic op that itself has a shift-by-constant operand with...
bool matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is known to be a power of 2.
bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
If MI is G_CONCAT_VECTORS, try to combine it.
bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) const
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
LLVMContext & getContext() const
void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
Combine inverting a result of a compare into the opposite cond code.
bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
Match sext_inreg(load p), imm -> sextload p.
bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine select to integer min/max.
void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst) const
Transform fp_instr(cst) to constant result of the fp operation.
bool isLegal(const LegalityQuery &Query) const
bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo) const
bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo) const
Try to reassociate to reassociate operands of a commutative binop.
void eraseInst(MachineInstr &MI) const
Erase MI.
bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo) const
Do constant FP folding when opportunities are exposed after MIR building.
void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
bool matchUndefStore(MachineInstr &MI) const
Return true if a G_STORE instruction MI is storing an undef value.
MachineRegisterInfo & MRI
void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg) const
Transform PtrToInt(IntToPtr(x)) to x.
void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
bool matchConstantFPOp(const MachineOperand &MOP, double C) const
Return true if MOP is defined by a G_FCONSTANT or splat with a value exactly equal to C.
void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo) const
Push a binary operator through a select on constants.
bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount) const
bool tryCombineExtendingLoads(MachineInstr &MI) const
If MI is extend that consumes the result of a load, try to combine it.
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo) const
bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (and x, n), k -> ubfx x, pos, width.
bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
bool tryCombineShuffleVector(MachineInstr &MI) const
Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS.
void applyRotateOutOfRange(MachineInstr &MI) const
bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
bool matchUndefSelectCmp(MachineInstr &MI) const
Return true if a G_SELECT instruction MI has an undef comparison.
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
void replaceInstWithUndef(MachineInstr &MI) const
Replace an instruction with a G_IMPLICIT_DEF.
bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (X + Y) == X -> Y == 0 (X - Y) == X -> Y == 0 (X ^ Y) == X -> Y == 0 (X + Y) !...
bool matchOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
If a brcond's true block is not the fallthrough, make it so by inverting the condition and swapping o...
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelKnownBits *KB=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine addos.
void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine selects.
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchRotateOutOfRange(MachineInstr &MI) const
void applyExpandFPowI(MachineInstr &MI, int64_t Exponent) const
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
void setRegBank(Register Reg, const RegisterBank *RegBank) const
Set the register bank of Reg.
bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) const
Return true if a G_SELECT instruction MI has a constant comparison.
bool matchCommuteFPConstantToRHS(MachineInstr &MI) const
Match constant LHS FP ops that should be commuted.
void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info) const
bool matchRedundantOr(MachineInstr &MI, Register &Replacement) const
bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
bool matchConstantOp(const MachineOperand &MOP, int64_t C) const
Return true if MOP is defined by a G_CONSTANT or splat with a value equal to C.
void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
bool matchUMulHToLShr(MachineInstr &MI) const
MachineDominatorTree * MDT
void applyFunnelShiftToRotate(MachineInstr &MI) const
bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
const RegisterBankInfo * RBI
bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*MULO x, 0) -> 0 + no carry out.
bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
void applyUDivByConst(MachineInstr &MI) const
void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
const TargetRegisterInfo * TRI
bool matchRedundantAnd(MachineInstr &MI, Register &Replacement) const
bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI dominates UseMI.
GISelChangeObserver & Observer
void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
bool matchCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftSize, unsigned &ShiftVal) const
Reduce a shift by a constant to an unmerge and a shift on a half sized type.
bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ands.
bool matchSuboCarryOut(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo) const
Constant fold G_FMA/G_FMAD.
bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg) const
Transform zext(trunc(x)) to x.
bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is undef.
bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0) const
Optimize memcpy intrinsics et al, e.g.
bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyShuffleToExtract(MachineInstr &MI) const
bool matchSubAddSameReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (x + y) - y -> x (x + y) - x -> y x - (y + x) -> 0 - y x - (x + z) -> 0 - z.
bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg) const
Transform anyext(trunc(x)) to x.
void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
MachineIRBuilder & Builder
void applyCommuteBinOpOperands(MachineInstr &MI) const
void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) const
Delete MI and replace all of its uses with its OpIdx-th operand.
void applySextTruncSextLoad(MachineInstr &MI) const
MachineInstr * buildUDivUsingMul(MachineInstr &MI) const
Given an G_UDIV MI expressing a divide by constant, return an expression that implements it by multip...
const MachineFunction & getMachineFunction() const
MachineInstr * buildSDivUsingMul(MachineInstr &MI) const
Given an G_SDIV MI expressing a signed divide by constant, return an expression that implements it by...
bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal) const
bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent) const
Match FPOWI if it's safe to extend it into a series of multiplications.
void applyCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
void applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
bool matchAshrShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
Match ashr (shl x, C), C -> sext_inreg (C)
void applyCombineUnmergeZExtToZExt(MachineInstr &MI) const
ConstantFP - Floating Point Values [float, double].
const APFloat & getValue() const
const APFloat & getValueAPF() const
const APInt & getValue() const
Return the constant as an APInt value reference.
This class represents a range of values.
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 unsignedSubMayOverflow(const ConstantRange &Other) const
Return whether unsigned sub of the two ranges always/never overflows.
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.
OverflowResult signedSubMayOverflow(const ConstantRange &Other) const
Return whether signed sub of the two ranges always/never overflows.
This is an important base class in LLVM.
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 getCarryOutReg() const
Register getRHSReg() const
Register getLHSReg() const
Register getLHSReg() const
Register getRHSReg() const
Represents a G_BUILD_VECTOR.
Abstract class that contains various methods for clients to notify about changes.
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
Represents overflowing sub operations.
Represents an integer subtraction.
Represents a G_UNMERGE_VALUES.
unsigned getNumDefs() const
Returns the number of def registers.
Register getSourceReg() const
Get the unmerge source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr bool isByteSized() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
constexpr ElementCount getElementCount() const
constexpr LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
constexpr 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 MachineInstr *A, const MachineInstr *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 buildCast(const DstOp &Dst, const SrcOp &Src)
Build and insert an appropriate cast between two registers of equal size.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_ICMP Pred, Op0, Op1.
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 which may be 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...
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
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)
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
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)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
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.
const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
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.
EVT getApproximateEVTForLLT(LLT Ty, LLVMContext &Ctx)
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.
bool isUnknown() const
Returns true if we don't know any bits.
unsigned countMinLeadingZeros() const
Returns the minimum number of leading zero bits.
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.
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