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 {
223 if (
MI.getOpcode() != TargetOpcode::COPY)
232 MI.eraseFromParent();
254 if (OrigDef->
isPHI() || isa<GUnmerge>(OrigDef))
261 std::optional<MachineOperand> MaybePoisonOperand;
263 if (!Operand.isReg())
269 if (!MaybePoisonOperand)
270 MaybePoisonOperand = Operand;
279 if (!MaybePoisonOperand) {
282 cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
284 B.buildCopy(
DstOp, OrigOp);
289 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
290 LLT MaybePoisonOperandRegTy =
MRI.
getType(MaybePoisonOperandReg);
294 cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
297 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
308 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
309 "Invalid instruction");
319 assert(Def &&
"Operand not defined");
322 switch (Def->getOpcode()) {
323 case TargetOpcode::G_BUILD_VECTOR:
330 case TargetOpcode::G_IMPLICIT_DEF: {
339 "All undefs should have the same type");
343 EltIdx != EltEnd; ++EltIdx)
344 Ops.
push_back(Undef->getOperand(0).getReg());
355 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.
getType(Ops[0])}})) {
382 MI.eraseFromParent();
393 if (!ConcatMI1 || !ConcatMI2)
397 if (
MRI.
getType(ConcatMI1->getSourceReg(0)) !=
404 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
408 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
409 if (i + j >= Mask.size())
411 if (Mask[i + j] != -1)
415 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
418 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
419 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
420 if (i + j >= Mask.size())
422 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
428 Ops.
push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
430 Ops.
push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
431 ConcatMI1->getNumSources()));
439 {TargetOpcode::G_CONCAT_VECTORS,
440 {
MRI.
getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
463 MI.eraseFromParent();
477 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
478 "Invalid instruction kind");
503 if (DstNumElts < 2 * SrcNumElts && DstNumElts != 1)
508 if (DstNumElts % SrcNumElts != 0)
514 unsigned NumConcat = DstNumElts / SrcNumElts;
517 for (
unsigned i = 0; i != DstNumElts; ++i) {
524 if ((
Idx % SrcNumElts != (i % SrcNumElts)) ||
525 (ConcatSrcs[i / SrcNumElts] >= 0 &&
526 ConcatSrcs[i / SrcNumElts] != (
int)(
Idx / SrcNumElts)))
529 ConcatSrcs[i / SrcNumElts] =
Idx / SrcNumElts;
536 for (
auto Src : ConcatSrcs) {
562 MI.eraseFromParent();
567 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
568 "Invalid instruction kind");
571 return Mask.size() == 1;
578 int I =
MI.getOperand(3).getShuffleMask()[0];
583 if (
I >= Src1NumElts) {
584 SrcReg =
MI.getOperand(2).getReg();
596 MI.eraseFromParent();
605 const LLT TyForCandidate,
606 unsigned OpcodeForCandidate,
611 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
622 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
625 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
626 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
627 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
633 if (!isa<GZExtLoad>(LoadMI) && CurrentUse.
Ty == TyForCandidate) {
635 OpcodeForCandidate == TargetOpcode::G_ZEXT)
637 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
638 OpcodeForCandidate == TargetOpcode::G_SEXT)
639 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
648 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
659static void InsertInsnsWithoutSideEffectsBeforeUse(
671 InsertBB = PredBB->
getMBB();
676 if (InsertBB ==
DefMI.getParent()) {
678 Inserter(InsertBB, std::next(InsertPt), UseMO);
697 unsigned CandidateLoadOpc;
699 case TargetOpcode::G_ANYEXT:
700 CandidateLoadOpc = TargetOpcode::G_LOAD;
702 case TargetOpcode::G_SEXT:
703 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
705 case TargetOpcode::G_ZEXT:
706 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
711 return CandidateLoadOpc;
742 if (!llvm::has_single_bit<uint32_t>(LoadValueTy.
getSizeInBits()))
750 unsigned PreferredOpcode =
752 ? TargetOpcode::G_ANYEXT
753 : isa<GSExtLoad>(&
MI) ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
754 Preferred = {
LLT(), PreferredOpcode,
nullptr};
756 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
757 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
758 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
759 const auto &MMO = LoadMI->
getMMO();
769 if (
LI->
getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
773 Preferred = ChoosePreferredUse(
MI, Preferred,
784 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
802 if (PreviouslyEmitted) {
812 EmittedInsns[InsertIntoBB] = NewMI;
824 Uses.push_back(&UseMO);
826 for (
auto *UseMO :
Uses) {
836 if (UseDstReg != ChosenDstReg) {
837 if (Preferred.
Ty == UseDstTy) {
874 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
889 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
892 MI.getOperand(0).setReg(ChosenDstReg);
898 assert(
MI.getOpcode() == TargetOpcode::G_AND);
917 APInt MaskVal = MaybeMask->Value;
938 if (MaskSizeBits > LoadSizeBits.
getValue())
958 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
964 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.
getType(PtrReg)}, {MemDesc}}))
968 B.setInstrAndDebugLoc(*LoadMI);
969 auto &MF =
B.getMF();
971 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
972 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
981 "shouldn't consider debug uses");
989 if (DefOrUse ==
MBB.
end())
991 return &*DefOrUse == &
DefMI;
997 "shouldn't consider debug uses");
1000 else if (
DefMI.getParent() !=
UseMI.getParent())
1007 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1016 LoadUser = TruncSrc;
1018 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1021 if (
auto *LoadMI = getOpcodeDef<GSExtLoad>(LoadUser,
MRI)) {
1023 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1027 if (LoadSizeBits == SizeInBits)
1034 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1036 MI.eraseFromParent();
1041 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1051 auto *LoadDef = getOpcodeDef<GLoad>(SrcReg,
MRI);
1055 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1060 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1063 if (NewSizeBits < 8)
1075 if (LoadDef->isSimple())
1077 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1087 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1093 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1095 unsigned ScalarSizeBits;
1096 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1105 auto &MMO = LoadDef->
getMMO();
1108 auto PtrInfo = MMO.getPointerInfo();
1112 MI.eraseFromParent();
1120 auto *MF =
MI->getMF();
1121 auto *
Addr = getOpcodeDef<GPtrAdd>(
MI->getPointerReg(),
MRI);
1127 AM.
BaseOffs = CstOff->getSExtValue();
1132 MF->getDataLayout(), AM,
1134 MF->getFunction().getContext()),
1135 MI->getMMO().getAddrSpace());
1140 case TargetOpcode::G_LOAD:
1141 return TargetOpcode::G_INDEXED_LOAD;
1142 case TargetOpcode::G_STORE:
1143 return TargetOpcode::G_INDEXED_STORE;
1144 case TargetOpcode::G_ZEXTLOAD:
1145 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1146 case TargetOpcode::G_SEXTLOAD:
1147 return TargetOpcode::G_INDEXED_SEXTLOAD;
1153bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1163 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1164 OpTys = {PtrTy, Ty, Ty};
1166 OpTys = {Ty, PtrTy};
1174 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1175 "considered for post-indexing."));
1179 bool &RematOffset) {
1192 if (!isIndexedLoadStoreLegal(LdSt))
1201 unsigned NumUsesChecked = 0;
1206 auto *PtrAdd = dyn_cast<GPtrAdd>(&
Use);
1214 if (StoredValDef == &
Use)
1217 Offset = PtrAdd->getOffsetReg();
1219 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1225 RematOffset =
false;
1229 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1235 if (&BasePtrUse == PtrDef)
1240 auto *BasePtrLdSt = dyn_cast<GLoadStore>(&BasePtrUse);
1241 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1243 isIndexedLoadStoreLegal(*BasePtrLdSt))
1248 if (
auto *BasePtrUseDef = dyn_cast<GPtrAdd>(&BasePtrUse)) {
1249 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1253 if (BaseUseUse.getParent() != LdSt.
getParent())
1256 if (
auto *UseUseLdSt = dyn_cast<GLoadStore>(&BaseUseUse))
1265 Addr = PtrAdd->getReg(0);
1266 Base = PtrAdd->getBaseReg();
1287 if (!isIndexedLoadStoreLegal(LdSt))
1291 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1294 if (
auto *St = dyn_cast<GStore>(&LdSt)) {
1296 if (
Base == St->getValueReg())
1301 if (St->getValueReg() ==
Addr)
1307 if (AddrUse.getParent() != LdSt.
getParent())
1312 bool RealUse =
false;
1319 if (
auto *UseLdSt = dyn_cast<GLoadStore>(&AddrUse)) {
1331 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1334 auto *LoadMI = getOpcodeDef<GLoad>(
MI.getOperand(1).getReg(),
MRI);
1348 if (!LoadMI->isSimple())
1360 const unsigned MaxIter = 20;
1363 if (
II->isLoadFoldBarrier())
1365 if (Iter++ == MaxIter)
1381 int Elt = CVal->getZExtValue();
1394 Register VecPtr = LoadMI->getPointerReg();
1402 LegalityQuery Q = {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}};
1427 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1437 auto &LdSt = cast<GLoadStore>(
MI);
1442 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1444 if (!MatchInfo.
IsPre &&
1445 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1455 unsigned Opcode =
MI.getOpcode();
1456 bool IsStore = Opcode == TargetOpcode::G_STORE;
1464 *OldCst->getOperand(1).getCImm());
1465 MatchInfo.
Offset = NewCst.getReg(0);
1471 MIB.
addUse(
MI.getOperand(0).getReg());
1473 MIB.
addDef(
MI.getOperand(0).getReg());
1481 MI.eraseFromParent();
1489 unsigned Opcode =
MI.getOpcode();
1490 bool IsDiv, IsSigned;
1495 case TargetOpcode::G_SDIV:
1496 case TargetOpcode::G_UDIV: {
1498 IsSigned = Opcode == TargetOpcode::G_SDIV;
1501 case TargetOpcode::G_SREM:
1502 case TargetOpcode::G_UREM: {
1504 IsSigned = Opcode == TargetOpcode::G_SREM;
1510 unsigned DivOpcode, RemOpcode, DivremOpcode;
1512 DivOpcode = TargetOpcode::G_SDIV;
1513 RemOpcode = TargetOpcode::G_SREM;
1514 DivremOpcode = TargetOpcode::G_SDIVREM;
1516 DivOpcode = TargetOpcode::G_UDIV;
1517 RemOpcode = TargetOpcode::G_UREM;
1518 DivremOpcode = TargetOpcode::G_UDIVREM;
1537 if (
MI.getParent() ==
UseMI.getParent() &&
1538 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1539 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1552 unsigned Opcode =
MI.getOpcode();
1553 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1556 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1557 DestDivReg =
MI.getOperand(0).getReg();
1561 DestRemReg =
MI.getOperand(0).getReg();
1565 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1575 : TargetOpcode::G_UDIVREM,
1576 {DestDivReg, DestRemReg},
1578 MI.eraseFromParent();
1584 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1603 assert(std::next(BrIt) ==
MBB->
end() &&
"expected G_BR to be a terminator");
1605 BrCond = &*std::prev(BrIt);
1606 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1612 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1630 MI.getOperand(0).setMBB(FallthroughBB);
1646 return Helper.lowerMemcpyInline(
MI) ==
1662 switch (
MI.getOpcode()) {
1665 case TargetOpcode::G_FNEG: {
1666 Result.changeSign();
1669 case TargetOpcode::G_FABS: {
1673 case TargetOpcode::G_FPTRUNC: {
1675 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1680 case TargetOpcode::G_FSQRT: {
1684 Result =
APFloat(sqrt(Result.convertToDouble()));
1687 case TargetOpcode::G_FLOG2: {
1708 MI.eraseFromParent();
1719 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1729 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1742 Type *AccessTy =
nullptr;
1743 auto &MF = *
MI.getMF();
1745 if (
auto *LdSt = dyn_cast<GLoadStore>(&
UseMI)) {
1747 MF.getFunction().getContext());
1752 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1757 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1760 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1761 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1762 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1775 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1781 MI.getOperand(1).setReg(MatchInfo.
Base);
1782 MI.getOperand(2).setReg(NewOffset.getReg(0));
1795 unsigned Opcode =
MI.getOpcode();
1796 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1797 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1798 Opcode == TargetOpcode::G_USHLSAT) &&
1799 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1819 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1824 if (Opcode == TargetOpcode::G_USHLSAT &&
1833 unsigned Opcode =
MI.getOpcode();
1834 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1835 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1836 Opcode == TargetOpcode::G_USHLSAT) &&
1837 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1841 auto Imm = MatchInfo.
Imm;
1843 if (Imm >= ScalarSizeInBits) {
1845 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1847 MI.eraseFromParent();
1852 Imm = ScalarSizeInBits - 1;
1858 MI.getOperand(1).setReg(MatchInfo.
Reg);
1859 MI.getOperand(2).setReg(NewImm);
1875 unsigned ShiftOpcode =
MI.getOpcode();
1876 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1877 ShiftOpcode == TargetOpcode::G_ASHR ||
1878 ShiftOpcode == TargetOpcode::G_LSHR ||
1879 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1880 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1881 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1884 Register LogicDest =
MI.getOperand(1).getReg();
1889 unsigned LogicOpcode = LogicMI->
getOpcode();
1890 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1891 LogicOpcode != TargetOpcode::G_XOR)
1895 const Register C1 =
MI.getOperand(2).getReg();
1897 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1900 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1904 if (
MI->getOpcode() != ShiftOpcode ||
1914 ShiftVal = MaybeImmVal->Value.getSExtValue();
1925 if (matchFirstShift(LogicMIOp1, C0Val)) {
1927 MatchInfo.
Shift2 = LogicMIOp1;
1928 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
1930 MatchInfo.
Shift2 = LogicMIOp2;
1934 MatchInfo.
ValSum = C0Val + C1Val;
1940 MatchInfo.
Logic = LogicMI;
1946 unsigned Opcode =
MI.getOpcode();
1947 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1948 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
1949 Opcode == TargetOpcode::G_SSHLSAT) &&
1950 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1968 Register Shift2Const =
MI.getOperand(2).getReg();
1980 MI.eraseFromParent();
1984 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
1987 auto &Shl = cast<GenericMachineInstr>(
MI);
2007 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2008 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2011 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2012 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2013 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {
S1, S2});
2019 unsigned &ShiftVal) {
2020 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2026 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2027 return (
static_cast<int32_t
>(ShiftVal) != -1);
2031 unsigned &ShiftVal) {
2032 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2037 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2038 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2045 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
KB);
2060 if (!MaybeShiftAmtVal)
2074 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2075 MatchData.
Reg = ExtSrc;
2076 MatchData.
Imm = ShiftAmt;
2080 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2086 int64_t ShiftAmtVal = MatchData.
Imm;
2093 MI.eraseFromParent();
2100 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2103 auto *Unmerge = getOpcodeDef<GUnmerge>(MergedValues[0],
MRI);
2104 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2107 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2108 if (MergedValues[
I] != Unmerge->getReg(
I))
2111 MatchInfo = Unmerge->getSourceReg();
2125 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2126 "Expected an unmerge");
2127 auto &Unmerge = cast<GUnmerge>(
MI);
2130 auto *SrcInstr = getOpcodeDef<GMergeLikeInstr>(SrcReg,
MRI);
2138 if (SrcMergeTy != Dst0Ty && !SameSize)
2142 for (
unsigned Idx = 0;
Idx < SrcInstr->getNumSources(); ++
Idx)
2149 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2150 "Expected an unmerge");
2152 "Not enough operands to replace all defs");
2153 unsigned NumElems =
MI.getNumOperands() - 1;
2157 bool CanReuseInputDirectly = DstTy == SrcTy;
2158 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2170 if (CanReuseInputDirectly)
2175 MI.eraseFromParent();
2180 unsigned SrcIdx =
MI.getNumOperands() - 1;
2181 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2183 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2184 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2195 for (
unsigned Idx = 0;
Idx != SrcIdx; ++
Idx) {
2197 Val = Val.
lshr(ShiftAmt);
2205 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2206 "Expected an unmerge");
2208 "Not enough operands to replace all defs");
2209 unsigned NumElems =
MI.getNumOperands() - 1;
2210 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2215 MI.eraseFromParent();
2220 unsigned SrcIdx =
MI.getNumOperands() - 1;
2221 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2223 unsigned NumElems =
MI.getNumOperands() - 1;
2224 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2226 B.buildUndef(DstReg);
2233 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2234 "Expected an unmerge");
2239 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs();
Idx != EndIdx; ++
Idx) {
2247 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2248 Register Dst0Reg =
MI.getOperand(0).getReg();
2250 MI.eraseFromParent();
2254 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2255 "Expected an unmerge");
2256 Register Dst0Reg =
MI.getOperand(0).getReg();
2263 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2280 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2281 "Expected an unmerge");
2283 Register Dst0Reg =
MI.getOperand(0).getReg();
2288 "Expecting a G_ZEXT");
2298 "ZExt src doesn't fit in destination");
2303 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs();
Idx != EndIdx; ++
Idx) {
2308 MI.eraseFromParent();
2312 unsigned TargetShiftSize,
2313 unsigned &ShiftVal) {
2314 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2315 MI.getOpcode() == TargetOpcode::G_LSHR ||
2316 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2324 if (
Size <= TargetShiftSize)
2332 ShiftVal = MaybeImmVal->Value.getSExtValue();
2333 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2337 const unsigned &ShiftVal) {
2342 unsigned HalfSize =
Size / 2;
2343 assert(ShiftVal >= HalfSize);
2348 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2350 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2351 Register Narrowed = Unmerge.getReg(1);
2358 if (NarrowShiftAmt != 0) {
2365 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2366 Register Narrowed = Unmerge.getReg(0);
2371 if (NarrowShiftAmt != 0) {
2379 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2381 HalfTy, Unmerge.getReg(1),
2384 if (ShiftVal == HalfSize) {
2388 }
else if (ShiftVal ==
Size - 1) {
2396 HalfTy, Unmerge.getReg(1),
2405 MI.eraseFromParent();
2409 unsigned TargetShiftAmount) {
2420 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2429 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2432 MI.eraseFromParent();
2436 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2439 MI.eraseFromParent();
2444 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2451 PtrReg.second =
false;
2461 PtrReg.second =
true;
2473 const bool DoCommute = PtrReg.second;
2482 MI.eraseFromParent();
2487 auto &PtrAdd = cast<GPtrAdd>(
MI);
2498 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2508 auto &PtrAdd = cast<GPtrAdd>(
MI);
2512 PtrAdd.eraseFromParent();
2516 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2521 SrcReg = OriginalSrcReg;
2528 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2546 if (ShiftSize > 32 && TruncSize < 32)
2560 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2577 case TargetOpcode::G_SHL: {
2586 case TargetOpcode::G_LSHR:
2587 case TargetOpcode::G_ASHR: {
2594 if (
User.getOpcode() == TargetOpcode::G_STORE)
2598 if (NewShiftTy == SrcTy)
2612 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2615 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2622 LLT NewShiftTy = MatchInfo.second;
2636 if (NewShiftTy == DstTy)
2646 return MO.isReg() &&
2647 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2653 return !MO.isReg() ||
2654 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2659 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2661 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2665 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2666 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2671 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2672 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2677 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2678 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2679 "Expected an insert/extract element op");
2682 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2695 OpIdx = Cst->isZero() ? 3 : 2;
2740 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2767 return MO.isReg() && MO.getReg().isPhysical();
2777 return I1->isIdenticalTo(*I2);
2792 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2803 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2804 MaybeCst->getSExtValue() ==
C;
2810 std::optional<FPValueAndVReg> MaybeCst;
2814 return MaybeCst->Value.isExactlyValue(
C);
2819 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2821 Register Replacement =
MI.getOperand(OpIdx).getReg();
2823 MI.eraseFromParent();
2829 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2832 MI.eraseFromParent();
2837 unsigned ConstIdx) {
2838 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
2851 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
2852 MI.getOpcode() == TargetOpcode::G_FSHR) &&
2853 "This is not a funnel shift operation");
2855 Register ConstReg =
MI.getOperand(3).getReg();
2860 assert((VRegAndVal) &&
"Value is not a constant");
2863 APInt NewConst = VRegAndVal->Value.
urem(
2868 MI.getOpcode(), {MI.getOperand(0)},
2869 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
2871 MI.eraseFromParent();
2875 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2896 return MO.
isReg() &&
2907 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2909 MI.eraseFromParent();
2913 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2915 MI.eraseFromParent();
2919 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2921 MI.eraseFromParent();
2926 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2928 MI.eraseFromParent();
2932 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2934 MI.eraseFromParent();
2941 Register &NewLHS = std::get<0>(MatchInfo);
2942 Register &NewRHS = std::get<1>(MatchInfo);
2950 NewLHS = MaybeNewLHS;
2959 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
2968 TargetOpcode::G_INSERT_VECTOR_ELT)
2974 MatchInfo.
resize(NumElts);
2978 if (IntImm >= NumElts || IntImm < 0)
2980 if (!MatchInfo[IntImm])
2981 MatchInfo[IntImm] = TmpReg;
2985 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
2987 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
2996 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3003 auto GetUndef = [&]() {
3015 MI.eraseFromParent();
3021 std::tie(SubLHS, SubRHS) = MatchInfo;
3023 MI.eraseFromParent();
3034 unsigned LogicOpcode =
MI.getOpcode();
3035 assert(LogicOpcode == TargetOpcode::G_AND ||
3036 LogicOpcode == TargetOpcode::G_OR ||
3037 LogicOpcode == TargetOpcode::G_XOR);
3050 if (!LeftHandInst || !RightHandInst)
3052 unsigned HandOpcode = LeftHandInst->
getOpcode();
3053 if (HandOpcode != RightHandInst->
getOpcode())
3065 if (!XTy.
isValid() || XTy != YTy)
3070 switch (HandOpcode) {
3073 case TargetOpcode::G_ANYEXT:
3074 case TargetOpcode::G_SEXT:
3075 case TargetOpcode::G_ZEXT: {
3079 case TargetOpcode::G_TRUNC: {
3095 case TargetOpcode::G_AND:
3096 case TargetOpcode::G_ASHR:
3097 case TargetOpcode::G_LSHR:
3098 case TargetOpcode::G_SHL: {
3103 ExtraHandOpSrcReg = ZOp.
getReg();
3125 if (ExtraHandOpSrcReg.
isValid())
3137 "Expected at least one instr to build?");
3139 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3140 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3142 for (
auto &OperandFn : InstrToBuild.OperandFns)
3145 MI.eraseFromParent();
3150 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3151 int64_t ShlCst, AshrCst;
3157 if (ShlCst != AshrCst)
3160 {TargetOpcode::G_SEXT_INREG, {
MRI.
getType(Src)}}))
3162 MatchInfo = std::make_tuple(Src, ShlCst);
3168 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3171 std::tie(Src, ShiftAmt) = MatchInfo;
3174 MI.eraseFromParent();
3180 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3195 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3198 auto Zero =
B.buildConstant(Ty, 0);
3221 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3245 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3252 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3268 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3286 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3293 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3304 unsigned ExtBits =
MI.getOperand(2).getImm();
3310 int64_t Cst,
bool IsVector,
bool IsFP) {
3312 return (ScalarSizeBits == 1 && Cst == -1) ||
3318 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3338 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3343 switch (Def->getOpcode()) {
3348 case TargetOpcode::G_ICMP:
3354 case TargetOpcode::G_FCMP:
3360 case TargetOpcode::G_AND:
3361 case TargetOpcode::G_OR:
3367 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3368 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3395 for (
Register Reg : RegsToNegate) {
3400 switch (Def->getOpcode()) {
3403 case TargetOpcode::G_ICMP:
3404 case TargetOpcode::G_FCMP: {
3411 case TargetOpcode::G_AND:
3414 case TargetOpcode::G_OR:
3422 MI.eraseFromParent();
3428 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3432 Register SharedReg =
MI.getOperand(2).getReg();
3453 return Y == SharedReg;
3460 std::tie(
X,
Y) = MatchInfo;
3464 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3465 MI.getOperand(2).setReg(
Y);
3470 auto &PtrAdd = cast<GPtrAdd>(
MI);
3471 Register DstReg = PtrAdd.getReg(0);
3480 return ConstVal && *ConstVal == 0;
3489 auto &PtrAdd = cast<GPtrAdd>(
MI);
3491 PtrAdd.eraseFromParent();
3498 Register Pow2Src1 =
MI.getOperand(2).getReg();
3505 MI.eraseFromParent();
3509 unsigned &SelectOpNo) {
3519 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3521 OtherOperandReg =
LHS;
3524 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3541 unsigned BinOpcode =
MI.getOpcode();
3546 bool CanFoldNonConst =
3547 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3552 if (CanFoldNonConst)
3563 const unsigned &SelectOperand) {
3574 unsigned BinOpcode =
MI.getOpcode();
3581 if (SelectOperand == 1) {
3595 MI.eraseFromParent();
3598std::optional<SmallVector<Register, 8>>
3599CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3600 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3629 const unsigned MaxIter =
3631 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3640 return std::nullopt;
3656 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
3657 return std::nullopt;
3669static std::optional<std::pair<GZExtLoad *, int64_t>>
3673 "Expected Reg to only have one non-debug use?");
3682 if (Shift % MemSizeInBits != 0)
3683 return std::nullopt;
3686 auto *Load = getOpcodeDef<GZExtLoad>(MaybeLoad,
MRI);
3688 return std::nullopt;
3690 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
3691 return std::nullopt;
3693 return std::make_pair(Load, Shift / MemSizeInBits);
3696std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
3697CombinerHelper::findLoadOffsetsForLoadOrCombine(
3731 for (
auto Reg : RegsToVisit) {
3736 return std::nullopt;
3739 std::tie(Load, DstPos) = *LoadAndPos;
3747 return std::nullopt;
3750 auto &LoadMMO =
Load->getMMO();
3754 return std::nullopt;
3761 LoadPtr =
Load->getOperand(1).getReg();
3767 return std::nullopt;
3774 if (BasePtr != LoadPtr)
3775 return std::nullopt;
3777 if (
Idx < LowestIdx) {
3779 LowestIdxLoad =
Load;
3787 return std::nullopt;
3795 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
3796 EarliestLoad =
Load;
3797 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
3804 "Expected to find a load for each register?");
3805 assert(EarliestLoad != LatestLoad && EarliestLoad &&
3806 LatestLoad &&
"Expected at least two loads?");
3815 const unsigned MaxIter = 20;
3821 if (
MI.isLoadFoldBarrier())
3822 return std::nullopt;
3823 if (Iter++ == MaxIter)
3824 return std::nullopt;
3827 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
3832 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3852 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
3856 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
3863 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
3864 if (NarrowMemSizeInBits % 8 != 0)
3877 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
3878 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
3881 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
3888 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
3891 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
3903 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
3904 const unsigned ZeroByteOffset =
3908 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
3909 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
3910 ZeroOffsetIdx->second != LowestIdx)
3934 MIB.setInstrAndDebugLoc(*LatestLoad);
3936 MIB.buildLoad(LoadDst,
Ptr, *NewMMO);
3938 MIB.buildBSwap(Dst, LoadDst);
3945 auto &
PHI = cast<GPhi>(
MI);
3958 case TargetOpcode::G_ANYEXT:
3960 case TargetOpcode::G_ZEXT:
3961 case TargetOpcode::G_SEXT:
3975 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
3978 case TargetOpcode::G_LOAD:
3979 case TargetOpcode::G_TRUNC:
3980 case TargetOpcode::G_SEXT:
3981 case TargetOpcode::G_ZEXT:
3982 case TargetOpcode::G_ANYEXT:
3983 case TargetOpcode::G_CONSTANT:
3987 if (InSrcs.
size() > 2)
3999 auto &
PHI = cast<GPhi>(
MI);
4008 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4009 auto SrcReg =
PHI.getIncomingValue(
I);
4011 if (!SrcMIs.
insert(SrcMI))
4017 if (InsertPt !=
MBB->
end() && InsertPt->isPHI())
4023 OldToNewSrcMap[SrcMI] = NewExt;
4032 NewPhi.
addMBB(MO.getMBB());
4036 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4044 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4054 unsigned VecIdx = Cst->Value.getZExtValue();
4059 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4063 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4064 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4084 if (ScalarTy != DstTy) {
4087 MI.eraseFromParent();
4096 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4119 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4124 unsigned Idx = Cst->getZExtValue();
4128 SrcDstPairs.emplace_back(
4129 std::make_pair(
MI.getOperand(
Idx + 1).getReg(), &
II));
4132 return ExtractedElts.
all();
4138 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4139 for (
auto &Pair : SrcDstPairs) {
4140 auto *ExtMI = Pair.second;
4142 ExtMI->eraseFromParent();
4144 MI.eraseFromParent();
4150 MI.eraseFromParent();
4160 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4166 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4167 unsigned FshOpc = 0;
4178 int64_t CstShlAmt, CstLShrAmt;
4181 CstShlAmt + CstLShrAmt ==
BitWidth) {
4182 FshOpc = TargetOpcode::G_FSHR;
4189 FshOpc = TargetOpcode::G_FSHL;
4195 FshOpc = TargetOpcode::G_FSHR;
4206 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4213 unsigned Opc =
MI.getOpcode();
4214 assert(Opc == TargetOpcode::G_FSHL || Opc == TargetOpcode::G_FSHR);
4219 unsigned RotateOpc =
4220 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4225 unsigned Opc =
MI.getOpcode();
4226 assert(Opc == TargetOpcode::G_FSHL || Opc == TargetOpcode::G_FSHR);
4227 bool IsFSHL = Opc == TargetOpcode::G_FSHL;
4230 : TargetOpcode::G_ROTR));
4231 MI.removeOperand(2);
4237 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4238 MI.getOpcode() == TargetOpcode::G_ROTR);
4242 bool OutOfRange =
false;
4243 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4244 if (
auto *CI = dyn_cast<ConstantInt>(
C))
4245 OutOfRange |= CI->getValue().uge(Bitsize);
4252 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4253 MI.getOpcode() == TargetOpcode::G_ROTR);
4261 MI.getOperand(2).setReg(Amt);
4266 int64_t &MatchInfo) {
4267 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4279 if (KnownRHS.isUnknown())
4282 std::optional<bool> KnownVal;
4283 if (KnownRHS.isZero()) {
4344 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4369 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4375 unsigned Op = TargetOpcode::COPY;
4376 if (DstSize != LHSSize)
4377 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4387 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4397 int64_t AndMaskBits;
4405 if (AndMaskBits & OrMaskBits)
4411 if (
MI.getOperand(1).getReg() == AndMaskReg)
4412 MI.getOperand(2).setReg(AndMaskReg);
4413 MI.getOperand(1).setReg(Src);
4422 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4429 int64_t Width =
MI.getOperand(2).getImm();
4441 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4442 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4443 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4460 int64_t AndImm, LSBImm;
4469 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4470 if (MaybeMask & (MaybeMask + 1))
4479 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4480 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4481 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4488 const unsigned Opcode =
MI.getOpcode();
4489 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4491 const Register Dst =
MI.getOperand(0).getReg();
4493 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4494 ? TargetOpcode::G_SBFX
4495 : TargetOpcode::G_UBFX;
4516 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4520 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4524 const int64_t Pos = ShrAmt - ShlAmt;
4525 const int64_t Width =
Size - ShrAmt;
4528 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4529 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4530 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4537 const unsigned Opcode =
MI.getOpcode();
4538 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4540 const Register Dst =
MI.getOperand(0).getReg();
4557 if (ShrAmt < 0 || ShrAmt >=
Size)
4561 if (0 == (SMask >> ShrAmt)) {
4563 B.buildConstant(Dst, 0);
4570 UMask |= maskTrailingOnes<uint64_t>(ShrAmt);
4571 UMask &= maskTrailingOnes<uint64_t>(
Size);
4576 const int64_t Pos = ShrAmt;
4581 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4585 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4586 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4587 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4592bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4594 auto &PtrAdd = cast<GPtrAdd>(
MI);
4596 Register Src1Reg = PtrAdd.getBaseReg();
4597 auto *Src1Def = getOpcodeDef<GPtrAdd>(Src1Reg,
MRI);
4601 Register Src2Reg = PtrAdd.getOffsetReg();
4613 const APInt &C1APIntVal = *C1;
4614 const APInt &C2APIntVal = *C2;
4615 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4621 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4622 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4623 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4630 auto *LdStMI = dyn_cast<GLoadStore>(ConvUseMI);
4641 PtrAdd.getMF()->getFunction().getContext());
4642 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4643 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4649 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4661 Register Src1Reg =
MI.getOperand(1).getReg();
4662 if (
RHS->getOpcode() != TargetOpcode::G_ADD)
4674 MI.getOperand(1).setReg(NewBase.getReg(0));
4675 MI.getOperand(2).setReg(
RHS->getOperand(2).getReg());
4678 return !reassociationCanBreakAddressingModePattern(
MI);
4688 std::optional<ValueAndVReg> LHSCstOff;
4693 auto *LHSPtrAdd = cast<GPtrAdd>(
LHS);
4698 LHSPtrAdd->moveBefore(&
MI);
4701 auto NewCst =
B.buildConstant(
MRI.
getType(RHSReg), LHSCstOff->Value);
4703 MI.getOperand(2).setReg(NewCst.getReg(0));
4706 LHSPtrAdd->getOperand(2).setReg(RHSReg);
4709 return !reassociationCanBreakAddressingModePattern(
MI);
4717 auto *LHSPtrAdd = dyn_cast<GPtrAdd>(
LHS);
4721 Register Src2Reg =
MI.getOperand(2).getReg();
4722 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
4723 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
4732 auto NewCst =
B.buildConstant(
MRI.
getType(Src2Reg), *C1 + *C2);
4734 MI.getOperand(1).setReg(LHSSrc1);
4735 MI.getOperand(2).setReg(NewCst.getReg(0));
4738 return !reassociationCanBreakAddressingModePattern(
MI);
4743 auto &PtrAdd = cast<GPtrAdd>(
MI);
4795 auto NewCst =
B.buildInstr(Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
4796 B.buildInstr(Opc, {DstReg}, {OpLHSLHS, NewCst});
4804 auto NewLHSLHS =
B.buildInstr(Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
4805 B.buildInstr(Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
4818 unsigned Opc =
MI.getOpcode();
4835 MatchInfo = *MaybeCst;
4848 MatchInfo = *MaybeCst;
4859 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
4865 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
4866 MI.getOpcode() == TargetOpcode::G_FMAD);
4867 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
4884 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
4906 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4930 case TargetOpcode::G_ADD:
4931 case TargetOpcode::G_SUB:
4932 case TargetOpcode::G_MUL:
4933 case TargetOpcode::G_AND:
4934 case TargetOpcode::G_OR:
4935 case TargetOpcode::G_XOR:
4943 auto Mask = Cst->Value;
4948 unsigned NarrowWidth = Mask.countr_one();
4954 auto &MF = *
MI.getMF();
4957 auto &
DL = MF.getDataLayout();
4958 if (!TLI.isTruncateFree(WideTy, NarrowTy,
DL, Ctx) ||
4959 !TLI.isZExtFree(NarrowTy, WideTy,
DL, Ctx))
4973 MI.getOperand(1).setReg(Ext.getReg(0));
4980 unsigned Opc =
MI.getOpcode();
4981 assert(Opc == TargetOpcode::G_UMULO || Opc == TargetOpcode::G_SMULO);
4988 unsigned NewOpc = Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
4989 : TargetOpcode::G_SADDO;
4991 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
4999 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5000 MI.getOpcode() == TargetOpcode::G_SMULO);
5009 B.buildConstant(Dst, 0);
5010 B.buildConstant(Carry, 0);
5018 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5019 MI.getOpcode() == TargetOpcode::G_SADDE ||
5020 MI.getOpcode() == TargetOpcode::G_USUBE ||
5021 MI.getOpcode() == TargetOpcode::G_SSUBE);
5026 switch (
MI.getOpcode()) {
5027 case TargetOpcode::G_UADDE:
5028 NewOpcode = TargetOpcode::G_UADDO;
5030 case TargetOpcode::G_SADDE:
5031 NewOpcode = TargetOpcode::G_SADDO;
5033 case TargetOpcode::G_USUBE:
5034 NewOpcode = TargetOpcode::G_USUBO;
5036 case TargetOpcode::G_SSUBE:
5037 NewOpcode = TargetOpcode::G_SSUBO;
5041 MI.setDesc(
B.getTII().get(NewOpcode));
5042 MI.removeOperand(4);
5050 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5084 B.buildSub(Dst, Zero, ReplaceReg);
5093 assert(
MI.getOpcode() == TargetOpcode::G_UDIV);
5094 auto &UDiv = cast<GenericMachineInstr>(
MI);
5106 bool UseSRL =
false;
5111 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5113 if (IsSplat && !Factors.
empty()) {
5119 auto *CI = cast<ConstantInt>(
C);
5120 APInt Divisor = CI->getValue();
5129 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5130 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5141 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5142 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5145 Factor = Factors[0];
5153 return MIB.buildMul(Ty, Res, Factor);
5156 unsigned KnownLeadingZeros =
5159 bool UseNPQ =
false;
5161 auto BuildUDIVPattern = [&](
const Constant *
C) {
5162 auto *CI = cast<ConstantInt>(
C);
5163 const APInt &Divisor = CI->getValue();
5165 bool SelNPQ =
false;
5167 unsigned PreShift = 0, PostShift = 0;
5172 if (!Divisor.
isOne()) {
5178 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5180 Magic = std::move(magics.
Magic);
5183 "We shouldn't generate an undefined shift!");
5185 "We shouldn't generate an undefined shift!");
5189 SelNPQ = magics.
IsAdd;
5193 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5194 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5196 MIB.buildConstant(ScalarTy,
5201 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5209 assert(Matched &&
"Expected unary predicate match to succeed");
5211 Register PreShift, PostShift, MagicFactor, NPQFactor;
5212 auto *RHSDef = getOpcodeDef<GBuildVector>(
RHS,
MRI);
5214 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5215 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5216 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5217 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5220 "Non-build_vector operation should have been a scalar");
5221 PreShift = PreShifts[0];
5222 MagicFactor = MagicFactors[0];
5223 PostShift = PostShifts[0];
5227 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5230 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5233 Register NPQ = MIB.buildSub(Ty,
LHS, Q).getReg(0);
5238 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5240 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5242 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5245 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5246 auto One = MIB.buildConstant(Ty, 1);
5247 auto IsOne = MIB.buildICmp(
5250 return MIB.buildSelect(Ty, IsOne,
LHS, Q);
5254 assert(
MI.getOpcode() == TargetOpcode::G_UDIV);
5259 auto &MF = *
MI.getMF();
5263 auto &
DL = MF.getDataLayout();
5269 if (MF.getFunction().hasMinSize())
5288 {TargetOpcode::G_ICMP,
5304 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5309 auto &MF = *
MI.getMF();
5313 auto &
DL = MF.getDataLayout();
5319 if (MF.getFunction().hasMinSize())
5338 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5339 auto &SDiv = cast<GenericMachineInstr>(
MI);
5349 bool UseSRA =
false;
5355 auto BuildSDIVPattern = [&](
const Constant *
C) {
5357 if (IsSplat && !Factors.
empty()) {
5363 auto *CI = cast<ConstantInt>(
C);
5364 APInt Divisor = CI->getValue();
5374 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5375 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5382 assert(Matched &&
"Expected unary predicate match to succeed");
5386 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5387 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5390 Factor = Factors[0];
5398 return MIB.buildMul(Ty, Res, Factor);
5402 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5403 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5404 "Expected SDIV or UDIV");
5405 auto &Div = cast<GenericMachineInstr>(
MI);
5407 auto MatchPow2 = [&](
const Constant *
C) {
5408 auto *CI = dyn_cast<ConstantInt>(
C);
5409 return CI && (CI->getValue().isPowerOf2() ||
5410 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5416 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5417 auto &SDiv = cast<GenericMachineInstr>(
MI);
5471 MI.eraseFromParent();
5475 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5476 auto &UDiv = cast<GenericMachineInstr>(
MI);
5485 MI.eraseFromParent();
5489 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
5494 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
5495 if (
auto *CI = dyn_cast<ConstantInt>(
C))
5496 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
5517 MI.eraseFromParent();
5522 unsigned Opc =
MI.getOpcode();
5523 assert(Opc == TargetOpcode::G_FADD || Opc == TargetOpcode::G_FSUB ||
5524 Opc == TargetOpcode::G_FMUL || Opc == TargetOpcode::G_FDIV ||
5525 Opc == TargetOpcode::G_FMAD || Opc == TargetOpcode::G_FMA);
5537 Opc = TargetOpcode::G_FSUB;
5542 Opc = TargetOpcode::G_FADD;
5548 else if ((Opc == TargetOpcode::G_FMUL || Opc == TargetOpcode::G_FDIV ||
5549 Opc == TargetOpcode::G_FMAD || Opc == TargetOpcode::G_FMA) &&
5558 MI.setDesc(
B.getTII().get(Opc));
5559 MI.getOperand(1).setReg(
X);
5560 MI.getOperand(2).setReg(
Y);
5567 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
5570 MatchInfo =
MI.getOperand(2).getReg();
5580 if (LHSCst->Value.isNegZero())
5584 if (LHSCst->Value.isPosZero())
5600 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
5608 MRI.use_instr_nodbg_end()) >
5610 MRI.use_instr_nodbg_end());
5614 bool &AllowFusionGlobally,
5616 bool CanReassociate) {
5618 auto *MF =
MI.getMF();
5619 const auto &TLI = *MF->getSubtarget().getTargetLowering();
5623 if (CanReassociate &&
5630 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
5633 if (!HasFMAD && !HasFMA)
5637 Options.UnsafeFPMath || HasFMAD;
5642 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
5648 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5650 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5658 unsigned PreferredFusedOpcode =
5659 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5673 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5674 {
LHS.MI->getOperand(1).getReg(),
5675 LHS.MI->getOperand(2).getReg(),
RHS.Reg});
5684 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5685 {
RHS.MI->getOperand(1).getReg(),
5686 RHS.MI->getOperand(2).getReg(),
LHS.Reg});
5696 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5698 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5702 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
5709 unsigned PreferredFusedOpcode =
5710 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5724 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5729 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5730 {FpExtX.getReg(0), FpExtY.getReg(0),
RHS.Reg});
5739 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5744 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5745 {FpExtX.getReg(0), FpExtY.getReg(0),
LHS.Reg});
5755 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5757 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5767 unsigned PreferredFusedOpcode =
5768 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5781 if (
LHS.MI->getOpcode() == PreferredFusedOpcode &&
5783 TargetOpcode::G_FMUL) &&
5790 else if (
RHS.MI->getOpcode() == PreferredFusedOpcode &&
5792 TargetOpcode::G_FMUL) &&
5801 Register X = FMA->getOperand(1).getReg();
5802 Register Y = FMA->getOperand(2).getReg();
5808 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
5809 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5820 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
5822 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5829 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
5836 unsigned PreferredFusedOpcode =
5837 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5850 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
5851 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
5853 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
5855 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5862 if (
LHS.MI->getOpcode() == PreferredFusedOpcode &&
5866 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5871 LHS.MI->getOperand(1).getReg(),
5872 LHS.MI->getOperand(2).getReg(),
B);
5883 FMAMI->
getOpcode() == PreferredFusedOpcode) {
5886 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5891 X =
B.buildFPExt(DstType,
X).getReg(0);
5892 Y =
B.buildFPExt(DstType,
Y).getReg(0);
5903 if (
RHS.MI->getOpcode() == PreferredFusedOpcode &&
5907 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5912 RHS.MI->getOperand(1).getReg(),
5913 RHS.MI->getOperand(2).getReg(),
B);
5924 FMAMI->
getOpcode() == PreferredFusedOpcode) {
5927 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
5932 X =
B.buildFPExt(DstType,
X).getReg(0);
5933 Y =
B.buildFPExt(DstType,
Y).getReg(0);
5946 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
5948 bool AllowFusionGlobally, HasFMAD,
Aggressive;
5960 int FirstMulHasFewerUses =
true;
5964 FirstMulHasFewerUses =
false;
5966 unsigned PreferredFusedOpcode =
5967 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
5970 if (FirstMulHasFewerUses &&
5975 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5976 {
LHS.MI->getOperand(1).getReg(),
5977 LHS.MI->getOperand(2).getReg(), NegZ});
5986 B.buildFNeg(DstTy,
RHS.MI->getOperand(1).getReg()).
getReg(0);
5987 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
5988 {NegY,
RHS.MI->getOperand(2).getReg(),
LHS.Reg});
5998 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6000 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6008 unsigned PreferredFusedOpcode =
6009 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6020 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6021 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6033 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6045 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6047 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6055 unsigned PreferredFusedOpcode =
6056 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6068 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6069 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6070 {FpExtX, FpExtY, NegZ});
6082 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6085 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6086 {NegY, FpExtZ, LHSReg});
6096 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6098 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6102 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6107 unsigned PreferredFusedOpcode =
6108 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6112 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6113 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6114 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6125 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6131 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6141 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6154 unsigned &IdxToPropagate) {
6156 switch (
MI.getOpcode()) {
6159 case TargetOpcode::G_FMINNUM:
6160 case TargetOpcode::G_FMAXNUM:
6161 PropagateNaN =
false;
6163 case TargetOpcode::G_FMINIMUM:
6164 case TargetOpcode::G_FMAXIMUM:
6165 PropagateNaN =
true;
6169 auto MatchNaN = [&](
unsigned Idx) {
6174 IdxToPropagate = PropagateNaN ?
Idx : (
Idx == 1 ? 2 : 1);
6178 return MatchNaN(1) || MatchNaN(2);
6182 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6192 Reg == MaybeSameReg;
6227 std::optional<ValueAndVReg> ShiftAmount;
6258 std::optional<ValueAndVReg> ShiftAmt;
6265 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
6269unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6271 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6272 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6273 "Expected a NaN behaviour?");
6283 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6284 return TargetOpcode::G_FMAXNUM;
6285 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6286 return TargetOpcode::G_FMAXIMUM;
6287 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6288 return TargetOpcode::G_FMAXNUM;
6289 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6290 return TargetOpcode::G_FMAXIMUM;
6296 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6297 return TargetOpcode::G_FMINNUM;
6298 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6299 return TargetOpcode::G_FMINIMUM;
6300 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6301 return TargetOpcode::G_FMINNUM;
6302 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6304 return TargetOpcode::G_FMINIMUM;
6308CombinerHelper::SelectPatternNaNBehaviour
6310 bool IsOrderedComparison)
const {
6314 if (!LHSSafe && !RHSSafe)
6315 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
6316 if (LHSSafe && RHSSafe)
6317 return SelectPatternNaNBehaviour::RETURNS_ANY;
6320 if (IsOrderedComparison)
6321 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
6322 : SelectPatternNaNBehaviour::RETURNS_OTHER;
6325 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
6326 : SelectPatternNaNBehaviour::RETURNS_NAN;
6348 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
6350 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
6352 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
6355 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
6356 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
6357 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
6358 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
6360 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
6363 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
6364 if (!Opc || !
isLegal({Opc, {DstTy}}))
6368 if (Opc != TargetOpcode::G_FMAXIMUM && Opc != TargetOpcode::G_FMINIMUM) {
6373 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
6375 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
6380 B.buildInstr(Opc, {Dst}, {CmpLHS, CmpRHS});
6388 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
6395 Register TrueVal =
MI.getOperand(2).getReg();
6396 Register FalseVal =
MI.getOperand(3).getReg();
6397 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
6402 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
6415 if (MatchedSub &&
X != OpLHS)
6423 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
6427 B.buildICmp(Pred, Dst,
Y, Zero);
6433 Register ShiftReg =
MI.getOperand(2).getReg();
6435 auto IsShiftTooBig = [&](
const Constant *
C) {
6436 auto *CI = dyn_cast<ConstantInt>(
C);
6443 unsigned LHSOpndIdx = 1;
6444 unsigned RHSOpndIdx = 2;
6445 switch (
MI.getOpcode()) {
6446 case TargetOpcode::G_UADDO:
6447 case TargetOpcode::G_SADDO:
6448 case TargetOpcode::G_UMULO:
6449 case TargetOpcode::G_SMULO:
6463 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
6468 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
6475 std::optional<FPValueAndVReg> ValAndVReg;
6483 unsigned LHSOpndIdx = 1;
6484 unsigned RHSOpndIdx = 2;
6485 switch (
MI.getOpcode()) {
6486 case TargetOpcode::G_UADDO:
6487 case TargetOpcode::G_SADDO:
6488 case TargetOpcode::G_UMULO:
6489 case TargetOpcode::G_SMULO:
6496 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
6497 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
6498 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
6499 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
6503bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs) {
6506 return isConstantSplatVector(Src, 1, AllowUndefs);
6508 if (AllowUndefs && getOpcodeDef<GImplicitDef>(Src,
MRI) !=
nullptr)
6511 return IConstant && IConstant->Value == 1;
6516bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs) {
6519 return isConstantSplatVector(Src, 0, AllowUndefs);
6521 if (AllowUndefs && getOpcodeDef<GImplicitDef>(Src,
MRI) !=
nullptr)
6524 return IConstant && IConstant->Value == 0;
6531bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
6538 for (
unsigned I = 0;
I < NumSources; ++
I) {
6541 if (ImplicitDef && AllowUndefs)
6543 if (ImplicitDef && !AllowUndefs)
6545 std::optional<ValueAndVReg> IConstant =
6547 if (IConstant && IConstant->Value == SplatValue)
6557CombinerHelper::getConstantOrConstantSplatVector(
Register Src) {
6560 return IConstant->Value;
6564 return std::nullopt;
6567 std::optional<APInt>
Value = std::nullopt;
6568 for (
unsigned I = 0;
I < NumSources; ++
I) {
6569 std::optional<ValueAndVReg> IConstant =
6572 return std::nullopt;
6576 return std::nullopt;
6582bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
6592 for (
unsigned I = 0;
I < NumSources; ++
I) {
6593 std::optional<ValueAndVReg> IConstant =
6602bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
6620 std::optional<ValueAndVReg> TrueOpt =
6622 std::optional<ValueAndVReg> FalseOpt =
6625 if (!TrueOpt || !FalseOpt)
6628 APInt TrueValue = TrueOpt->Value;
6629 APInt FalseValue = FalseOpt->Value;
6634 B.setInstrAndDebugLoc(*
Select);
6635 B.buildZExtOrTrunc(Dest,
Cond);
6643 B.setInstrAndDebugLoc(*
Select);
6644 B.buildSExtOrTrunc(Dest,
Cond);
6652 B.setInstrAndDebugLoc(*
Select);
6654 B.buildNot(Inner,
Cond);
6655 B.buildZExtOrTrunc(Dest, Inner);
6663 B.setInstrAndDebugLoc(*
Select);
6665 B.buildNot(Inner,
Cond);
6666 B.buildSExtOrTrunc(Dest, Inner);
6672 if (TrueValue - 1 == FalseValue) {
6674 B.setInstrAndDebugLoc(*
Select);
6676 B.buildZExtOrTrunc(Inner,
Cond);
6677 B.buildAdd(Dest, Inner, False);
6683 if (TrueValue + 1 == FalseValue) {
6685 B.setInstrAndDebugLoc(*
Select);
6687 B.buildSExtOrTrunc(Inner,
Cond);
6688 B.buildAdd(Dest, Inner, False);
6696 B.setInstrAndDebugLoc(*
Select);
6698 B.buildZExtOrTrunc(Inner,
Cond);
6701 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
6702 B.buildShl(Dest, Inner, ShAmtC, Flags);
6709 B.setInstrAndDebugLoc(*
Select);
6711 B.buildSExtOrTrunc(Inner,
Cond);
6712 B.buildOr(Dest, Inner, False, Flags);
6720 B.setInstrAndDebugLoc(*
Select);
6722 B.buildNot(Not,
Cond);
6724 B.buildSExtOrTrunc(Inner, Not);
6725 B.buildOr(Dest, Inner, True, Flags);
6734bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
6751 if (CondTy != TrueTy)
6756 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
6758 B.setInstrAndDebugLoc(*
Select);
6760 B.buildZExtOrTrunc(Ext,
Cond);
6761 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
6762 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
6769 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
6771 B.setInstrAndDebugLoc(*
Select);
6773 B.buildZExtOrTrunc(Ext,
Cond);
6774 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
6775 B.buildAnd(DstReg, Ext, FreezeTrue);
6781 if (isOneOrOneSplat(False,
true)) {
6783 B.setInstrAndDebugLoc(*
Select);
6786 B.buildNot(Inner,
Cond);
6789 B.buildZExtOrTrunc(Ext, Inner);
6790 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
6791 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
6797 if (isZeroOrZeroSplat(True,
true)) {
6799 B.setInstrAndDebugLoc(*
Select);
6802 B.buildNot(Inner,
Cond);
6805 B.buildZExtOrTrunc(Ext, Inner);
6806 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
6807 B.buildAnd(DstReg, Ext, FreezeFalse);
6838 Register CmpLHS = Cmp->getLHSReg();
6839 Register CmpRHS = Cmp->getRHSReg();
6842 if (True == CmpRHS && False == CmpLHS) {
6850 if (True != CmpLHS || False != CmpRHS)
6890 if (tryFoldSelectOfConstants(
Select, MatchInfo))
6893 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
6903bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
GLogicalBinOp *Logic,
6905 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
6906 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
6910 unsigned Flags = Logic->
getFlags();
6913 GICmp *Cmp1 = getOpcodeDef<GICmp>(LHS,
MRI);
6918 GICmp *Cmp2 = getOpcodeDef<GICmp>(RHS,
MRI);
6929 std::optional<ValueAndVReg> MaybeC1 =
6933 C1 = MaybeC1->Value;
6935 std::optional<ValueAndVReg> MaybeC2 =
6939 C2 = MaybeC2->Value;
6960 std::optional<APInt> Offset1;
6961 std::optional<APInt> Offset2;
6963 if (
GAdd *
Add = getOpcodeDef<GAdd>(R1,
MRI)) {
6964 std::optional<ValueAndVReg> MaybeOffset1 =
6967 R1 =
Add->getLHSReg();
6968 Offset1 = MaybeOffset1->Value;
6972 std::optional<ValueAndVReg> MaybeOffset2 =
6975 R2 =
Add->getLHSReg();
6976 Offset2 = MaybeOffset2->Value;
6995 bool CreateMask =
false;
7008 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7021 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7031 if (CreateMask &&
Offset != 0) {
7032 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7033 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7034 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7035 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7036 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7037 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7038 B.buildZExtOrTrunc(DstReg, ICmp);
7039 }
else if (CreateMask &&
Offset == 0) {
7040 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7041 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7042 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7043 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7044 B.buildZExtOrTrunc(DstReg, ICmp);
7045 }
else if (!CreateMask &&
Offset != 0) {
7046 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7047 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7048 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7049 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7050 B.buildZExtOrTrunc(DstReg, ICmp);
7051 }
else if (!CreateMask &&
Offset == 0) {
7052 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7053 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7054 B.buildZExtOrTrunc(DstReg, ICmp);
7062bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7068 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7071 GFCmp *Cmp1 = getOpcodeDef<GFCmp>(LHS,
MRI);
7076 GFCmp *Cmp2 = getOpcodeDef<GFCmp>(RHS,
MRI);
7086 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7100 if (LHS0 == RHS1 && LHS1 == RHS0) {
7106 if (LHS0 == RHS0 && LHS1 == RHS1) {
7110 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7117 auto False =
B.buildConstant(CmpTy, 0);
7118 B.buildZExtOrTrunc(DestReg, False);
7125 B.buildZExtOrTrunc(DestReg, True);
7127 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7128 B.buildZExtOrTrunc(DestReg, Cmp);
7140 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7143 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7152 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7155 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7169 bool IsSigned =
Add->isSigned();
7178 B.buildUndef(Carry);
7184 if (isConstantOrConstantVectorI(
LHS) && !isConstantOrConstantVectorI(
RHS)) {
7187 B.buildSAddo(Dst, Carry,
RHS,
LHS);
7193 B.buildUAddo(Dst, Carry,
RHS,
LHS);
7198 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(
LHS);
7199 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(
RHS);
7205 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7206 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7208 B.buildConstant(Dst, Result);
7209 B.buildConstant(Carry, Overflow);
7217 B.buildCopy(Dst,
LHS);
7218 B.buildConstant(Carry, 0);
7230 std::optional<APInt> MaybeAddRHS =
7231 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
7234 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
7235 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
7239 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7240 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7246 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7247 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7272 B.buildConstant(Carry, 0);
7280 B.buildConstant(Carry, 1);
7295 B.buildConstant(Carry, 0);
7311 B.buildConstant(Carry, 0);
7319 B.buildConstant(Carry, 1);
7336 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
7341 auto [Dst,
Base] =
MI.getFirst2Regs();
7347 MI.removeFromParent();
7359 std::optional<SrcOp> Res;
7361 while (ExpVal > 0) {
7380 MI.eraseFromParent();
7386 const GSub *Sub = cast<GSub>(&
MI);
7399 auto Const =
B.buildConstant(DstTy, C1 - C2);
7400 B.buildAdd(Dst,
Add->getLHSReg(), Const);
7409 const GSub *Sub = cast<GSub>(&
MI);
7422 auto Const =
B.buildConstant(DstTy, C2 - C1);
7423 B.buildSub(Dst, Const,
Add->getLHSReg());
7432 const GSub *Sub1 = cast<GSub>(&
MI);
7445 auto Const =
B.buildConstant(DstTy, C1 + C2);
7455 const GSub *Sub1 = cast<GSub>(&
MI);
7468 auto Const =
B.buildConstant(DstTy, C1 - C2);
7491 auto Const =
B.buildConstant(DstTy, C2 - C1);
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
amdgpu 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 cl::opt< unsigned > PostIndexUseThreshold("post-index-use-threshold", cl::Hidden, cl::init(32), cl::desc("Number of uses of a base pointer to check before it is no longer " "considered for post-indexing."))
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
static unsigned getExtLoadOpcForExtend(unsigned ExtOpc)
static bool isConstValidTrue(const TargetLowering &TLI, unsigned ScalarSizeBits, int64_t Cst, bool IsVector, bool IsFP)
static LLT getMidVTForTruncRightShiftCombine(LLT ShiftTy, LLT TruncTy)
static bool canFoldInAddressingMode(GLoadStore *MI, const TargetLowering &TLI, MachineRegisterInfo &MRI)
Return true if 'MI' is a load or a store that may be fold it's address operand into the load / store ...
static unsigned littleEndianByteAt(const unsigned ByteWidth, const unsigned I)
static Register buildLogBase2(Register V, MachineIRBuilder &MIB)
Determines the LogBase2 value for a non-null input value using the transform: LogBase2(V) = (EltBits ...
This contains common combine transformations that may be used in a combine pass,or by the target else...
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
Rewrite Partial Register Uses
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
Interface for Targets to specify which operations they can successfully select and how the others sho...
Implement a low-level type suitable for MachineInstr level instruction selection.
Contains matchers for matching SSA Machine Instructions.
mir Rename Register Operands
This file declares the MachineIRBuilder class.
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
uint64_t IntrinsicInst * II
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
const SmallVectorImpl< MachineOperand > & Cond
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
This file implements the SmallBitVector class.
This file describes how to lower LLVM code to machine code.
const fltSemantics & getSemantics() const
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM)
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
uint64_t getZExtValue() const
Get zero extended value.
APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
APInt trunc(unsigned width) const
Truncate to new width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
APInt urem(const APInt &RHS) const
Unsigned remainder operation.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
int32_t exactLogBase2() const
void ashrInPlace(unsigned ShiftAmt)
Arithmetic right-shift this APInt by ShiftAmt in place.
unsigned countr_zero() const
Count the number of trailing zero bits.
unsigned countl_zero() const
The APInt version of std::countl_zero.
APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
unsigned countl_one() const
Count the number of leading one bits.
APInt multiplicativeInverse() const
bool isMask(unsigned numBits) const
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
bool isOne() const
Determine if this is a value of 1.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
int64_t getSExtValue() const
Get sign extended value.
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 applyUDivByConst(MachineInstr &MI)
void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal)
bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops)
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
bool matchPtrAddZero(MachineInstr &MI)
}
bool matchAllExplicitUsesAreUndef(MachineInstr &MI)
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx)
Delete MI and replace all of its uses with its OpIdx-th operand.
const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo)
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
bool matchUDivByConst(MachineInstr &MI)
Combine G_UDIV by constant into a multiply by magic constant.
void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg)
bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI)
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
bool matchShiftsTooBig(MachineInstr &MI)
Match shifts greater or equal to the bitwidth of the operation.
bool tryCombineCopy(MachineInstr &MI)
If MI is COPY, try to combine it.
bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo)
bool matchUndefStore(MachineInstr &MI)
Return true if a G_STORE instruction MI is storing an undef value.
bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform: (X + Y) == X -> Y == 0 (X - Y) == X -> Y == 0 (X ^ Y) == X -> Y == 0 (X + Y) !...
bool matchRedundantSExtInReg(MachineInstr &MI)
bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo)
bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent)
Match FPOWI if it's safe to extend it into a series of multiplications.
bool matchSubAddSameReg(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform: (x + y) - y -> x (x + y) - x -> y x - (y + x) -> 0 - y x - (x + z) -> 0 - z.
bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo)
Do constant FP folding when opportunities are exposed after MIR building.
void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal)
void applyCombineUnmergeZExtToZExt(MachineInstr &MI)
void applyCommuteBinOpOperands(MachineInstr &MI)
bool matchBinOpSameVal(MachineInstr &MI)
Optimize (x op x) -> x.
void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts)
bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
bool matchCombineCopy(MachineInstr &MI)
bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx)
Return true if a G_SELECT instruction MI has a constant comparison.
void eraseInst(MachineInstr &MI)
Erase MI.
void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, Register ToReg) const
Replace a single register operand with a new register and inform the observer of the changes.
bool matchCombineFAddFMAFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y, (fma u, v, z)) (fadd (fmad x,...
void applySimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo)
bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops)
If MI is G_CONCAT_VECTORS, try to combine it.
bool matchAddSubSameReg(MachineInstr &MI, Register &Src)
Transform G_ADD(x, G_SUB(y, x)) to y.
void applyRotateOutOfRange(MachineInstr &MI)
const DataLayout & getDataLayout() const
bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: (G_UMULO x, 2) -> (G_UADDO x, x) (G_SMULO x, 2) -> (G_SADDO x, x)
bool matchRotateOutOfRange(MachineInstr &MI)
void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst)
void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo)
void applyCombineShuffleVector(MachineInstr &MI, const ArrayRef< Register > Ops)
Replace MI with a concat_vectors with Ops.
const TargetLowering & getTargetLowering() const
void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo)
Use a function which takes in a MachineIRBuilder to perform a combine.
void applyPtrAddZero(MachineInstr &MI)
bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo)
void setRegBank(Register Reg, const RegisterBank *RegBank)
Set the register bank of Reg.
bool matchRedundantAnd(MachineInstr &MI, Register &Replacement)
void replaceInstWithConstant(MachineInstr &MI, int64_t C)
Replace an instruction with a G_CONSTANT with value C.
bool matchAshrShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo)
Match ashr (shl x, C), C -> sext_inreg (C)
bool tryCombineExtendingLoads(MachineInstr &MI)
If MI is extend that consumes the result of a load, try to combine it.
bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount)
bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo)
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
void applySDivByConst(MachineInstr &MI)
bool matchUndefSelectCmp(MachineInstr &MI)
Return true if a G_SELECT instruction MI has an undef comparison.
void replaceInstWithUndef(MachineInstr &MI)
Replace an instruction with a G_IMPLICIT_DEF.
bool matchRedundantOr(MachineInstr &MI, Register &Replacement)
bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx)
Check if operand OpIdx is undef.
void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo)
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst)
void replaceInstWithFConstant(MachineInstr &MI, double C)
Replace an instruction with a G_FCONSTANT with value C.
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo)
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2)
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo)
Fold (shift (shift base, x), y) -> (shift base (x+y))
bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo)
void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo)
void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond)
bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: (G_*MULO x, 0) -> 0 + no carry out.
void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement)
Delete MI and replace all of its uses with Replacement.
bool matchFunnelShiftToRotate(MachineInstr &MI)
Match an FSHL or FSHR that can be combined to a ROTR or ROTL rotate.
bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate)
Combine inverting a result of a compare into the opposite cond code.
void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
bool matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI, unsigned OpIdx)
Check if operand OpIdx is known to be a power of 2.
bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo)
void applyCombineCopy(MachineInstr &MI)
bool matchAnyExplicitUseIsUndef(MachineInstr &MI)
Return true if any explicit use operand on MI is defined by a G_IMPLICIT_DEF.
bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo)
void applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute)
bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo)
void applyCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops)
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
bool matchSextTruncSextLoad(MachineInstr &MI)
bool matchShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo)
If we have a shift-by-constant of a bitwise logic op that itself has a shift-by-constant operand with...
bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo)
void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo)
MachineInstr * buildSDivUsingMul(MachineInstr &MI)
Given an G_SDIV MI expressing a signed divide by constant, return an expression that implements it by...
void applySDivByPow2(MachineInstr &MI)
void applyFunnelShiftConstantModulo(MachineInstr &MI)
Replaces the shift amount in MI with ShiftAmt % BW.
bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo)
Do constant folding when opportunities are exposed after MIR building.
bool isPreLegalize() const
bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo)
Match (and (load x), mask) -> zextload x.
bool matchConstantOp(const MachineOperand &MOP, int64_t C)
Return true if MOP is defined by a G_CONSTANT or splat with a value equal to C.
bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine ands.
void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg)
void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate)
void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo)
bool matchConstantFPOp(const MachineOperand &MOP, double C)
Return true if MOP is defined by a G_FCONSTANT or splat with a value exactly equal to C.
bool matchSimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo)
Return true if MI is a G_ADD which can be simplified to a G_SUB.
bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0)
Optimize memcpy intrinsics et al, e.g.
bool matchSelectSameVal(MachineInstr &MI)
Optimize (cond ? x : x) -> x.
void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst)
Transform fp_instr(cst) to constant result of the fp operation.
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo)
LLVMContext & getContext() const
bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo)
Try to reassociate to reassociate operands of a commutative binop.
bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
bool tryEmitMemcpyInline(MachineInstr &MI)
Emit loads and stores that perform the given memcpy.
void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo)
bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo)
Fold (xor (and x, y), y) -> (and (not x), y) {.
bool matchCombineFSubFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fsub (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), (fneg z)) (fsub (fpext (fmul x,...
bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info)
bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData)
bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo)
Constant fold G_FMA/G_FMAD.
bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo)
void applyExpandFPowI(MachineInstr &MI, int64_t Exponent)
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
bool isLegal(const LegalityQuery &Query) const
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine selects.
bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts)
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo)
bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg)
Transform anyext(trunc(x)) to x.
void applySimplifyURemByPow2(MachineInstr &MI)
Combine G_UREM x, (known power of 2) to an add and bitmasking.
bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo)
void applyCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops)
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
MachineRegisterInfo & MRI
void applyUMulHToLShr(MachineInstr &MI)
bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo)
Match expression trees of the form.
bool matchShuffleToExtract(MachineInstr &MI)
bool matchUndefShuffleVectorMask(MachineInstr &MI)
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI)
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal)
Transform a multiply by a power-of-2 value to a left shift.
bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo)
SelectOperand is the operand in binary operator MI that is the select to fold.
bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo)
bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fadd x, fneg(y)) -> (fsub x, y) (fadd fneg(x), y) -> (fsub y, x) (fsub x,...
bool matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo)
Fold away a merge of an unmerge of the corresponding values.
void applyCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo)
bool matchCombineUnmergeZExtToZExt(MachineInstr &MI)
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI)
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx)
Checks if constant at ConstIdx is larger than MI 's bitwidth.
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelKnownBits *KB=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
bool matchCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI)
Try to combine G_[SU]DIV and G_[SU]REM into a single G_[SU]DIVREM when their source operands are iden...
bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo)
bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI)
Returns true if DefMI precedes UseMI or they are the same instruction.
bool matchDivByPow2(MachineInstr &MI, bool IsSigned)
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg)
bool matchUMulHToLShr(MachineInstr &MI)
bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI)
Returns true if DefMI dominates UseMI.
MachineInstr * buildUDivUsingMul(MachineInstr &MI)
Given an G_UDIV MI expressing a divide by constant, return an expression that implements it by multip...
bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg)
Transform zext(trunc(x)) to x.
void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData)
bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false)
void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI)
void applyShuffleToExtract(MachineInstr &MI)
MachineDominatorTree * MDT
bool matchSDivByConst(MachineInstr &MI)
void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo)
bool matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands)
Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo)
void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo)
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo)
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
const RegisterBankInfo * RBI
bool matchCommuteShift(MachineInstr &MI, BuildFnTy &MatchInfo)
bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo)
void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI)
const TargetRegisterInfo * TRI
bool tryCombineShuffleVector(MachineInstr &MI)
Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS.
bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg)
Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo)
GISelChangeObserver & Observer
bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo)
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo)
Match sext_inreg(load p), imm -> sextload p.
bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo)
bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute)
Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) Transform G_ADD y,...
bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine ors.
void applyFunnelShiftToRotate(MachineInstr &MI)
void applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands)
bool matchOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond)
If a brcond's true block is not the fallthrough, make it so by inverting the condition and swapping o...
bool matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: (G_*ADDE x, y, 0) -> (G_*ADDO x, y) (G_*SUBE x, y, 0) -> (G_*SUBO x, y)
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine addos.
void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg)
Transform PtrToInt(IntToPtr(x)) to x.
bool matchCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftSize, unsigned &ShiftVal)
Reduce a shift by a constant to an unmerge and a shift on a half sized type.
bool matchCommuteConstantToRHS(MachineInstr &MI)
Match constant LHS ops that should be commuted.
bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo)
void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo)
void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI)
void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo)
void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo)
Replace MI with a series of instructions described in MatchInfo.
bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo)
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
MachineIRBuilder & Builder
bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine select to integer min/max.
bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo)
Match: shr (and x, n), k -> ubfx x, pos, width.
bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops)
bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo)
Reassociate commutative binary operations like G_ADD.
bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo)
Push a binary operator through a select on constants.
bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo)
Do constant folding when opportunities are exposed after MIR building.
const MachineFunction & getMachineFunction() const
bool matchOperandIsZero(MachineInstr &MI, unsigned OpIdx)
Check if operand OpIdx is zero.
bool matchOrShiftToFunnelShift(MachineInstr &MI, BuildFnTy &MatchInfo)
void applyUDivByPow2(MachineInstr &MI)
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo)
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo)
void applySextTruncSextLoad(MachineInstr &MI)
bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo)
bool matchCommuteFPConstantToRHS(MachineInstr &MI)
Match constant LHS FP ops that should be commuted.
ConstantFP - Floating Point Values [float, double].
const APFloat & getValue() const
const APFloat & getValueAPF() const
const APInt & getValue() const
Return the constant as an APInt value reference.
This class represents a range of values.
std::optional< ConstantRange > exactUnionWith(const ConstantRange &CR) const
Union the two ranges and return the result if it can be represented exactly, otherwise return std::nu...
ConstantRange subtract(const APInt &CI) const
Subtract the specified constant from the endpoints of this constant range.
static ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned)
Initialize a range based on a known bits constraint.
const APInt & getLower() const
Return the lower value for this range.
OverflowResult unsignedAddMayOverflow(const ConstantRange &Other) const
Return whether unsigned add of the two ranges always/never overflows.
bool isWrappedSet() const
Return true if this set wraps around the unsigned domain.
const APInt & getUpper() const
Return the upper value for this range.
static ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, const APInt &Other)
Produce the exact range such that all values in the returned range satisfy the given predicate with a...
OverflowResult signedAddMayOverflow(const ConstantRange &Other) const
Return whether signed add of the two ranges always/never overflows.
@ NeverOverflows
Never overflows.
@ AlwaysOverflowsHigh
Always overflows in the direction of signed/unsigned max value.
@ AlwaysOverflowsLow
Always overflows in the direction of signed/unsigned min value.
@ MayOverflow
May or may not overflow.
This is an important base class in LLVM.
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&... Args)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Represents overflowing add operations.
Represents an integer addition.
Represents a logical and.
CmpInst::Predicate getCond() const
Register getLHSReg() const
Register getRHSReg() const
Represents any generic load, including sign/zero extending variants.
Register getDstReg() const
Get the definition register of the loaded value.
Register getLHSReg() const
Register getRHSReg() const
Represents a G_BUILD_VECTOR.
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 an integer subtraction.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr bool isByteSized() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
constexpr ElementCount getElementCount() const
constexpr LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
constexpr unsigned getAddressSpace() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
constexpr LLT getScalarType() const
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
This is an important class for using LLVM in a threaded context.
@ Legalized
Instruction has been legalized and the MachineFunction changed.
LegalizeResult lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0)
Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
bool isLegalOrCustom(const LegalityQuery &Query) const
LegalizeActionStep getAction(const LegalityQuery &Query) const
Determine what action should be taken to legalize the described instruction.
TypeSize getValue() const
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
bool isLayoutSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB will be emitted immediately after this block, such that if this bloc...
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
bool dominates(const MachineDomTreeNode *A, const MachineDomTreeNode *B) const
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Helper class to build MachineInstr.
MachineInstrBuilder buildFMul(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder insertInstr(MachineInstrBuilder MIB)
Insert an existing instruction at the insertion point.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
LLVMContext & getContext() const
MachineInstrBuilder buildAdd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ADD Op0, Op1.
MachineInstrBuilder buildUndef(const DstOp &Res)
Build and insert Res = IMPLICIT_DEF.
MachineInstrBuilder buildNot(const DstOp &Dst, const SrcOp &Src0)
Build and insert a bitwise not, NegOne = G_CONSTANT -1 Res = G_OR Op0, NegOne.
MachineInstrBuilder buildCTTZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTTZ Op0, Src0.
MachineInstrBuilder buildAShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildUnmerge(ArrayRef< LLT > Res, const SrcOp &Op)
Build and insert Res0, ... = G_UNMERGE_VALUES Op.
MachineInstrBuilder buildSelect(const DstOp &Res, const SrcOp &Tst, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_SELECT Tst, Op0, Op1.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1)
Build and insert a Res = G_ICMP Pred, Op0, Op1.
MachineInstrBuilder buildCast(const DstOp &Dst, const SrcOp &Src)
Build and insert an appropriate cast between two registers of equal size.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildURem(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_UREM Op0, Op1.
MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildConcatVectors(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_CONCAT_VECTORS Op0, ...
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildIntToPtr(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_INTTOPTR instruction.
MachineInstrBuilder buildBuildVector(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ...
MachineInstrBuilder buildNeg(const DstOp &Dst, const SrcOp &Src0)
Build and insert integer negation Zero = G_CONSTANT 0 Res = G_SUB Zero, Op0.
MachineInstrBuilder buildCTLZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTLZ Op0, Src0.
MachineInstrBuilder buildFDiv(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_FDIV Op0, Op1.
MachineInstrBuilder buildMergeLikeInstr(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_MERGE_VALUES Op0, ... or Res = G_BUILD_VECTOR Op0, ... or Res = G_CONCAT_VEC...
MachineInstrBuilder buildPtrAdd(const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_PTR_ADD Op0, Op1.
MachineInstrBuilder buildZExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ZEXT Op, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes...
MachineInstrBuilder buildExtractVectorElementConstant(const DstOp &Res, const SrcOp &Val, const int Idx)
Build and insert Res = G_EXTRACT_VECTOR_ELT Val, Idx.
virtual MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val)
Build and insert Res = G_FCONSTANT Val.
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
MachineInstrBuilder buildExtOrTrunc(unsigned ExtOpc, const DstOp &Res, const SrcOp &Op)
Build and insert Res = ExtOpc, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes of...
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
void setDebugLoc(const DebugLoc &DL)
Set the debug location to DL for all the next build instructions.
MachineInstrBuilder buildFNeg(const DstOp &Dst, const SrcOp &Src0, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_FNEG Op0.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
MachineInstrBuilder buildInstrNoInsert(unsigned Opcode)
Build but don't insert <empty> = Opcode <empty>.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
MachineInstrBuilder buildLoadInstr(unsigned Opcode, const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = <opcode> Addr, MMO.
MachineInstrBuilder buildXor(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_XOR Op0, Op1.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
MachineInstrBuilder buildFCanonicalize(const DstOp &Dst, const SrcOp &Src0, std::optional< unsigned > Flags=std::nullopt)
Build and insert Dst = G_FCANONICALIZE Src0.
MachineInstrBuilder buildSExtInReg(const DstOp &Res, const SrcOp &Op, int64_t ImmOp)
Build and insert Res = G_SEXT_INREG Op, ImmOp.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
const MachineBasicBlock * getParent() const
bool isDereferenceableInvariantLoad() const
Return true if this load instruction never traps and points to a memory location whose value doesn't ...
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
iterator_range< mop_iterator > uses()
Returns a range that includes all operands that are register uses.
void cloneMemRefs(MachineFunction &MF, const MachineInstr &MI)
Clone another MachineInstr's memory reference descriptor list and replace ours with it.
unsigned getNumOperands() const
Retuns the total number of operands.
void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
int findRegisterDefOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isDead=false, bool Overlap=false) const
Returns the operand index that is a def of the specified register or -1 if it is not found.
A description of a memory reference used in the backend.
LLT getMemoryType() const
Return the memory type of the memory reference.
unsigned getAddrSpace() const
const MachinePointerInfo & getPointerInfo() const
Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
void setReg(Register Reg)
Change the register this operand corresponds to.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setMBB(MachineBasicBlock *MBB)
void setPredicate(unsigned Predicate)
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
unsigned getPredicate() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
use_instr_iterator use_instr_begin(Register RegNo) const
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
const RegClassOrRegBank & getRegClassOrRegBank(Register Reg) const
Return the register bank or register class of Reg.
void setRegClassOrRegBank(Register Reg, const RegClassOrRegBank &RCOrRB)
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
iterator_range< use_instr_iterator > use_instructions(Register Reg) const
Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
bool constrainRegAttrs(Register Reg, Register ConstrainingReg, unsigned MinNumRegs=0)
Constrain the register class or the register bank of the virtual register Reg (and low-level type) to...
iterator_range< use_iterator > use_operands(Register Reg) const
void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
size_type size() const
Determine the number of elements in the SetVector.
size_type count(const key_type &key) const
Count the number of elements of a given key in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
bool all() const
Returns true if all bits are set.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
virtual bool isExtendLikelyToBeFolded(MachineInstr &ExtMI, MachineRegisterInfo &MRI) const
Given the generic extension instruction ExtMI, returns true if this extension is a likely candidate f...
virtual bool produceSameValue(const MachineInstr &MI0, const MachineInstr &MI1, const MachineRegisterInfo *MRI=nullptr) const
Return true if two machine instructions would produce identical values.
virtual bool isZExtFree(Type *FromTy, Type *ToTy) const
Return true if any actual instruction that defines a value of type FromTy implicitly zero-extends the...
virtual bool isTruncateFree(Type *FromTy, Type *ToTy) const
Return true if it's free to truncate a value of type FromTy to type ToTy.
virtual LLVM_READONLY LLT getPreferredShiftAmountTy(LLT ShiftValueTy) const
Return the preferred type to use for a shift opcode, given the shifted amount type is ShiftValueTy.
bool isBeneficialToExpandPowI(int64_t Exponent, bool OptForSize) const
Return true if it is beneficial to expand an @llvm.powi.
virtual bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AddrSpace, Instruction *I=nullptr) const
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
virtual bool isReassocProfitable(SelectionDAG &DAG, SDValue N0, SDValue N1) const
virtual const TargetLowering * getTargetLowering() const
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Value(Type *Ty, unsigned scid)
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Fast
Attempts to make calls as fast as possible (e.g.
@ C
The default llvm calling convention, compatible with C.
@ Legal
The operation is expected to be selectable directly by the target, and no transformation is necessary...
operand_type_match m_Reg()
SpecificConstantOrSplatMatch m_SpecificICstOrSplat(int64_t RequestedValue)
Matches a RequestedValue constant or a constant splat of RequestedValue.
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false > m_GBuildVector(const LHS &L, const RHS &R)
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
SpecificConstantMatch m_SpecificICst(int64_t RequestedValue)
Matches a constant equal to RequestedValue.
operand_type_match m_Pred()
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_XOR, true > m_GXor(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_SEXT > m_GSExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_FPEXT > m_GFPExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
UnaryOp_match< SrcTy, TargetOpcode::G_INTTOPTR > m_GIntToPtr(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
CheckType m_SpecificType(LLT Ty)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FADD, true > m_GFAdd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_PTRTOINT > m_GPtrToInt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_BITCAST > m_GBitcast(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false > m_GBuildVectorTrunc(const LHS &L, const RHS &R)
bind_ty< MachineInstr * > m_MInstr(MachineInstr *&MI)
UnaryOp_match< SrcTy, TargetOpcode::G_FNEG > m_GFNeg(const SrcTy &Src)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP, true > m_c_GICmp(const Pred &P, const LHS &L, const RHS &R)
G_ICMP matcher that also matches commuted compares.
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_INSERT_VECTOR_ELT > m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
GFCstOrSplatGFCstMatch m_GFCstOrSplat(std::optional< FPValueAndVReg > &FPValReg)
And< Preds... > m_all_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_LSHR, false > m_GLShr(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ANYEXT > m_GAnyExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP > m_GFCmp(const Pred &P, const LHS &L, const RHS &R)
class_match< BinaryOperator > m_BinOp()
Match an arbitrary binary operation and ignore it.
BinaryOp_match< cst_pred_ty< is_zero_int >, ValTy, Instruction::Sub > m_Neg(const ValTy &V)
Matches a 'Neg' as 'sub 0, V'.
Not(const Pred &P) -> Not< Pred >
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool isBuildVectorAllZeros(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
static double log2(double V)
const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
EVT getApproximateEVTForLLT(LLT Ty, const DataLayout &DL, LLVMContext &Ctx)
std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
std::optional< APInt > getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI)
bool isAllOnesOrAllOnesSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant -1 integer or a splatted vector of a constant -1 integer (with...
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
std::optional< APFloat > ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
bool isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL, bool OrZero=false, unsigned Depth=0, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true)
Return true if the given value is known to have exactly one bit set when defined.
std::optional< APInt > isConstantOrConstantSplatVector(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a constant integer or a splat vector of constant integers.
bool isNullOrNullSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant 0 integer or a splatted vector of a constant 0 integer (with n...
MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, std::function< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
bool isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, bool IsFP)
Returns true if given the TargetLowering's boolean contents information, the value Val contains a tru...
std::function< void(MachineIRBuilder &)> BuildFnTy
std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
bool isConstantOrConstantVector(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowFP=true, bool AllowOpaqueConstants=true)
Return true if the specified instruction is known to be a constant, or a vector of constants.
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
bool canCreateUndefOrPoison(const Operator *Op, bool ConsiderFlagsAndMetadata=true)
canCreateUndefOrPoison returns true if Op can create undef or poison from non-undef & non-poison oper...
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
std::optional< FPValueAndVReg > getFConstantSplat(Register VReg, const MachineRegisterInfo &MRI, bool AllowUndef=true)
Returns a floating point scalar constant of a build vector splat if it exists.
std::optional< APInt > ConstantFoldCastOp(unsigned Opcode, LLT DstTy, const Register Op0, const MachineRegisterInfo &MRI)
@ Xor
Bitwise or logical XOR of integers.
DWARFExpression::Operation Op
APInt getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
std::optional< FPValueAndVReg > getFConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_FCONSTANT returns it...
constexpr unsigned BitWidth
int64_t getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP)
Returns an integer representing true, as defined by the TargetBooleanContents.
std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
bool isKnownNeverNaN(const Value *V, unsigned Depth, const SimplifyQuery &SQ)
Return true if the floating-point scalar value is not a NaN or if the floating-point vector value has...
Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
unsigned getFCmpCode(CmpInst::Predicate CC)
Similar to getICmpCode but for FCmpInst.
std::optional< int64_t > getIConstantSplatSExtVal(const Register Reg, const MachineRegisterInfo &MRI)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static constexpr roundingMode rmNearestTiesToEven
static const fltSemantics & IEEEdouble() LLVM_READNONE
This struct is a compact representation of a valid (non-zero power of two) alignment.
Simple struct used to hold a Register value and the instruction which defines it.
SmallVector< InstructionBuildSteps, 2 > InstrsToBuild
Describes instructions to be built during a combine.
static std::optional< bool > eq(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_EQ result.
bool isUnknown() const
Returns true if we don't know any bits.
static std::optional< bool > ne(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_NE result.
static std::optional< bool > sge(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_SGE result.
unsigned countMinLeadingZeros() const
Returns the minimum number of leading zero bits.
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.
static std::optional< bool > ugt(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_UGT result.
static std::optional< bool > slt(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_SLT result.
static std::optional< bool > ult(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_ULT result.
static std::optional< bool > ule(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_ULE result.
static std::optional< bool > sle(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_SLE result.
static std::optional< bool > sgt(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_SGT result.
static std::optional< bool > uge(const KnownBits &LHS, const KnownBits &RHS)
Determine if these known bits always give the same ICMP_UGE result.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
LegalizeAction Action
The action to take or the final answer.
This class contains a discriminated union of information about pointers in memory operands,...
unsigned getAddrSpace() const
Return the LLVM IR address space number that this pointer points into.
MachinePointerInfo getWithOffset(int64_t O) const
const RegisterBank * Bank
Register LogicNonShiftReg
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
Magic data for optimising unsigned division by a constant.
unsigned PreShift
pre-shift amount
static UnsignedDivisionByConstantInfo get(const APInt &D, unsigned LeadingZeros=0, bool AllowEvenDivisorOptimization=true)
Calculate the magic numbers required to implement an unsigned integer division by a constant as a seq...
unsigned PostShift
post-shift amount