45#define DEBUG_TYPE "vector-combine"
51STATISTIC(NumVecLoad,
"Number of vector loads formed");
52STATISTIC(NumVecCmp,
"Number of vector compares formed");
53STATISTIC(NumVecBO,
"Number of vector binops formed");
54STATISTIC(NumVecCmpBO,
"Number of vector compare + binop formed");
55STATISTIC(NumShufOfBitcast,
"Number of shuffles moved after bitcast");
56STATISTIC(NumScalarOps,
"Number of scalar unary + binary ops formed");
57STATISTIC(NumScalarCmp,
"Number of scalar compares formed");
58STATISTIC(NumScalarIntrinsic,
"Number of scalar intrinsic calls formed");
62 cl::desc(
"Disable all vector combine transforms"));
66 cl::desc(
"Disable binop extract to shuffle transforms"));
70 cl::desc(
"Max number of instructions to scan for vector combining."));
72static const unsigned InvalidIndex = std::numeric_limits<unsigned>::max();
80 bool TryEarlyFoldsOnly)
83 SQ(*
DL, nullptr, &DT, &AC),
84 TryEarlyFoldsOnly(TryEarlyFoldsOnly) {}
91 const TargetTransformInfo &TTI;
92 const DominatorTree &DT;
96 const SimplifyQuery SQ;
100 bool TryEarlyFoldsOnly;
102 InstructionWorklist Worklist;
111 bool vectorizeLoadInsert(Instruction &
I);
112 bool widenSubvectorLoad(Instruction &
I);
113 ExtractElementInst *getShuffleExtract(ExtractElementInst *Ext0,
114 ExtractElementInst *Ext1,
115 unsigned PreferredExtractIndex)
const;
116 bool isExtractExtractCheap(ExtractElementInst *Ext0, ExtractElementInst *Ext1,
117 const Instruction &
I,
118 ExtractElementInst *&ConvertToShuffle,
119 unsigned PreferredExtractIndex);
122 bool foldExtractExtract(Instruction &
I);
123 bool foldInsExtFNeg(Instruction &
I);
124 bool foldInsExtBinop(Instruction &
I);
125 bool foldInsExtVectorToShuffle(Instruction &
I);
126 bool foldBitOpOfCastops(Instruction &
I);
127 bool foldBitOpOfCastConstant(Instruction &
I);
128 bool foldBitcastShuffle(Instruction &
I);
129 bool scalarizeOpOrCmp(Instruction &
I);
130 bool scalarizeVPIntrinsic(Instruction &
I);
131 bool foldExtractedCmps(Instruction &
I);
132 bool foldSelectsFromBitcast(Instruction &
I);
133 bool foldBinopOfReductions(Instruction &
I);
134 bool foldSingleElementStore(Instruction &
I);
135 bool scalarizeLoad(Instruction &
I);
136 bool scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
Value *Ptr);
137 bool scalarizeLoadBitcast(LoadInst *LI, VectorType *VecTy,
Value *Ptr);
138 bool scalarizeExtExtract(Instruction &
I);
139 bool foldConcatOfBoolMasks(Instruction &
I);
140 bool foldPermuteOfBinops(Instruction &
I);
141 bool foldShuffleOfBinops(Instruction &
I);
142 bool foldShuffleOfSelects(Instruction &
I);
143 bool foldShuffleOfCastops(Instruction &
I);
144 bool foldShuffleOfShuffles(Instruction &
I);
145 bool foldPermuteOfIntrinsic(Instruction &
I);
146 bool foldShufflesOfLengthChangingShuffles(Instruction &
I);
147 bool foldShuffleOfIntrinsics(Instruction &
I);
148 bool foldShuffleToIdentity(Instruction &
I);
149 bool foldShuffleFromReductions(Instruction &
I);
150 bool foldShuffleChainsToReduce(Instruction &
I);
151 bool foldCastFromReductions(Instruction &
I);
152 bool foldSignBitReductionCmp(Instruction &
I);
153 bool foldReductionZeroTest(Instruction &
I);
154 bool foldICmpEqZeroVectorReduce(Instruction &
I);
155 bool foldEquivalentReductionCmp(Instruction &
I);
156 bool foldReduceAddCmpZero(Instruction &
I);
157 bool foldSelectShuffle(Instruction &
I,
bool FromReduction =
false);
158 bool foldInterleaveIntrinsics(Instruction &
I);
159 bool foldDeinterleaveIntrinsics(Instruction &
I);
160 bool foldBitcastOfVPLoad(Instruction &
I);
161 bool foldBitOrderReverseAndSwap(Instruction &
I);
162 bool shrinkType(Instruction &
I);
163 bool shrinkLoadForShuffles(Instruction &
I);
164 bool shrinkPhiOfShuffles(Instruction &
I);
166 void replaceValue(Instruction &Old,
Value &New,
bool Erase =
true) {
172 Worklist.pushUsersToWorkList(*NewI);
173 Worklist.pushValue(NewI);
190 SmallPtrSet<Value *, 4> Visited;
195 OpI,
nullptr,
nullptr, [&](
Value *V) {
200 NextInst = NextInst->getNextNode();
205 Worklist.pushUsersToWorkList(*OpI);
206 Worklist.pushValue(OpI);
226 if (!Load || !Load->isSimple() || !Load->hasOneUse() ||
227 Load->getFunction()->hasFnAttribute(Attribute::SanitizeMemTag) ||
233 Type *ScalarTy = Load->getType()->getScalarType();
235 unsigned MinVectorSize =
TTI.getMinVectorRegisterBitWidth();
236 if (!ScalarSize || !MinVectorSize || MinVectorSize % ScalarSize != 0 ||
243bool VectorCombine::vectorizeLoadInsert(
Instruction &
I) {
269 Value *SrcPtr =
Load->getPointerOperand()->stripPointerCasts();
272 unsigned MinVecNumElts = MinVectorSize / ScalarSize;
273 auto *MinVecTy = VectorType::get(ScalarTy, MinVecNumElts,
false);
274 unsigned OffsetEltIndex = 0;
282 unsigned OffsetBitWidth =
DL->getIndexTypeSizeInBits(SrcPtr->
getType());
283 APInt
Offset(OffsetBitWidth, 0);
293 uint64_t ScalarSizeInBytes = ScalarSize / 8;
294 if (
Offset.urem(ScalarSizeInBytes) != 0)
298 OffsetEltIndex =
Offset.udiv(ScalarSizeInBytes).getZExtValue();
299 if (OffsetEltIndex >= MinVecNumElts)
316 unsigned AS =
Load->getPointerAddressSpace();
335 unsigned OutputNumElts = Ty->getNumElements();
337 assert(OffsetEltIndex < MinVecNumElts &&
"Address offset too big");
338 Mask[0] = OffsetEltIndex;
345 if (OldCost < NewCost || !NewCost.
isValid())
356 replaceValue(
I, *VecLd);
364bool VectorCombine::widenSubvectorLoad(Instruction &
I) {
367 if (!Shuf->isIdentityWithPadding())
373 unsigned OpIndex =
any_of(Shuf->getShuffleMask(), [&NumOpElts](
int M) {
374 return M >= (int)(NumOpElts);
385 Value *SrcPtr =
Load->getPointerOperand()->stripPointerCasts();
394 unsigned AS =
Load->getPointerAddressSpace();
409 if (OldCost < NewCost || !NewCost.
isValid())
416 replaceValue(
I, *VecLd);
423ExtractElementInst *VectorCombine::getShuffleExtract(
424 ExtractElementInst *Ext0, ExtractElementInst *Ext1,
428 assert(Index0C && Index1C &&
"Expected constant extract indexes");
430 unsigned Index0 = Index0C->getZExtValue();
431 unsigned Index1 = Index1C->getZExtValue();
434 if (Index0 == Index1)
458 if (PreferredExtractIndex == Index0)
460 if (PreferredExtractIndex == Index1)
464 return Index0 > Index1 ? Ext0 : Ext1;
472bool VectorCombine::isExtractExtractCheap(ExtractElementInst *Ext0,
473 ExtractElementInst *Ext1,
474 const Instruction &
I,
475 ExtractElementInst *&ConvertToShuffle,
476 unsigned PreferredExtractIndex) {
479 assert(Ext0IndexC && Ext1IndexC &&
"Expected constant extract indexes");
481 unsigned Opcode =
I.getOpcode();
494 assert((Opcode == Instruction::ICmp || Opcode == Instruction::FCmp) &&
495 "Expected a compare");
505 unsigned Ext0Index = Ext0IndexC->getZExtValue();
506 unsigned Ext1Index = Ext1IndexC->getZExtValue();
520 unsigned BestExtIndex = Extract0Cost > Extract1Cost ? Ext0Index : Ext1Index;
521 unsigned BestInsIndex = Extract0Cost > Extract1Cost ? Ext1Index : Ext0Index;
522 InstructionCost CheapExtractCost = std::min(Extract0Cost, Extract1Cost);
527 if (Ext0Src == Ext1Src && Ext0Index == Ext1Index) {
532 bool HasUseTax = Ext0 == Ext1 ? !Ext0->
hasNUses(2)
534 OldCost = CheapExtractCost + ScalarOpCost;
535 NewCost = VectorOpCost + CheapExtractCost + HasUseTax * CheapExtractCost;
539 OldCost = Extract0Cost + Extract1Cost + ScalarOpCost;
540 NewCost = VectorOpCost + CheapExtractCost +
545 ConvertToShuffle = getShuffleExtract(Ext0, Ext1, PreferredExtractIndex);
546 if (ConvertToShuffle) {
558 SmallVector<int> ShuffleMask(FixedVecTy->getNumElements(),
560 ShuffleMask[BestInsIndex] = BestExtIndex;
562 VecTy, VecTy, ShuffleMask,
CostKind, 0,
563 nullptr, {ConvertToShuffle});
566 VecTy, VecTy, {},
CostKind, 0,
nullptr,
571 LLVM_DEBUG(
dbgs() <<
"Found a binop of extractions: " <<
I <<
"\n OldCost: "
572 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
577 return OldCost < NewCost;
589 ShufMask[NewIndex] = OldIndex;
590 return Builder.CreateShuffleVector(Vec, ShufMask,
"shift");
642 V1,
"foldExtExtBinop");
647 VecBOInst->copyIRFlags(&
I);
653bool VectorCombine::foldExtractExtract(Instruction &
I) {
674 unsigned NumElts = FixedVecTy->getNumElements();
675 if (C0 >= NumElts || C1 >= NumElts)
691 ExtractElementInst *ExtractToChange;
692 if (isExtractExtractCheap(Ext0, Ext1,
I, ExtractToChange, InsertIndex))
698 if (ExtractToChange) {
699 unsigned CheapExtractIdx = ExtractToChange == Ext0 ? C1 : C0;
704 if (ExtractToChange == Ext0)
713 ? foldExtExtCmp(ExtOp0, ExtOp1, ExtIndex,
I)
714 : foldExtExtBinop(ExtOp0, ExtOp1, ExtIndex,
I);
717 replaceValue(
I, *NewExt);
723bool VectorCombine::foldInsExtFNeg(Instruction &
I) {
726 uint64_t ExtIdx, InsIdx;
741 auto *DstVecScalarTy = DstVecTy->getScalarType();
743 if (!SrcVecTy || DstVecScalarTy != SrcVecTy->getScalarType())
748 unsigned NumDstElts = DstVecTy->getNumElements();
749 unsigned NumSrcElts = SrcVecTy->getNumElements();
750 if (ExtIdx > NumSrcElts || InsIdx >= NumDstElts || NumDstElts == 1)
756 SmallVector<int>
Mask(NumDstElts);
757 std::iota(
Mask.begin(),
Mask.end(), 0);
758 Mask[InsIdx] = (ExtIdx % NumDstElts) + NumDstElts;
774 bool NeedLenChg = SrcVecTy->getNumElements() != NumDstElts;
777 SmallVector<int> SrcMask;
780 SrcMask[ExtIdx % NumDstElts] = ExtIdx;
782 DstVecTy, SrcVecTy, SrcMask,
CostKind);
786 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
788 if (NewCost > OldCost)
791 Value *NewShuf, *LenChgShuf =
nullptr;
805 replaceValue(
I, *NewShuf);
811bool VectorCombine::foldInsExtBinop(Instruction &
I) {
812 BinaryOperator *VecBinOp, *SclBinOp;
844 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
846 if (NewCost > OldCost)
857 NewInst->copyIRFlags(VecBinOp);
858 NewInst->andIRFlags(SclBinOp);
863 replaceValue(
I, *NewBO);
869bool VectorCombine::foldBitOpOfCastops(Instruction &
I) {
872 if (!BinOp || !BinOp->isBitwiseLogicOp())
878 if (!LHSCast || !RHSCast) {
879 LLVM_DEBUG(
dbgs() <<
" One or both operands are not cast instructions\n");
885 if (CastOpcode != RHSCast->getOpcode())
889 switch (CastOpcode) {
890 case Instruction::BitCast:
891 case Instruction::Trunc:
892 case Instruction::SExt:
893 case Instruction::ZExt:
899 Value *LHSSrc = LHSCast->getOperand(0);
900 Value *RHSSrc = RHSCast->getOperand(0);
906 auto *SrcTy = LHSSrc->
getType();
907 auto *DstTy =
I.getType();
910 if (CastOpcode != Instruction::BitCast &&
915 if (!SrcTy->getScalarType()->isIntegerTy() ||
916 !DstTy->getScalarType()->isIntegerTy())
931 LHSCastCost + RHSCastCost;
942 if (!LHSCast->hasOneUse())
943 NewCost += LHSCastCost;
944 if (!RHSCast->hasOneUse())
945 NewCost += RHSCastCost;
948 <<
" NewCost=" << NewCost <<
"\n");
950 if (NewCost > OldCost)
955 BinOp->getName() +
".inner");
957 NewBinOp->copyIRFlags(BinOp);
971 replaceValue(
I, *Result);
980bool VectorCombine::foldBitOpOfCastConstant(Instruction &
I) {
996 switch (CastOpcode) {
997 case Instruction::BitCast:
998 case Instruction::ZExt:
999 case Instruction::SExt:
1000 case Instruction::Trunc:
1006 Value *LHSSrc = LHSCast->getOperand(0);
1008 auto *SrcTy = LHSSrc->
getType();
1009 auto *DstTy =
I.getType();
1012 if (CastOpcode != Instruction::BitCast &&
1017 if (!SrcTy->getScalarType()->isIntegerTy() ||
1018 !DstTy->getScalarType()->isIntegerTy())
1022 PreservedCastFlags RHSFlags;
1047 if (!LHSCast->hasOneUse())
1048 NewCost += LHSCastCost;
1050 LLVM_DEBUG(
dbgs() <<
"foldBitOpOfCastConstant: OldCost=" << OldCost
1051 <<
" NewCost=" << NewCost <<
"\n");
1053 if (NewCost > OldCost)
1058 LHSSrc, InvC,
I.getName() +
".inner");
1060 NewBinOp->copyIRFlags(&
I);
1080 replaceValue(
I, *Result);
1087bool VectorCombine::foldBitcastShuffle(Instruction &
I) {
1101 if (!DestTy || !SrcTy)
1104 unsigned DestEltSize = DestTy->getScalarSizeInBits();
1105 unsigned SrcEltSize = SrcTy->getScalarSizeInBits();
1106 if (SrcTy->getPrimitiveSizeInBits() % DestEltSize != 0)
1116 if (!(BCTy0 && BCTy0->getElementType() == DestTy->getElementType()) &&
1117 !(BCTy1 && BCTy1->getElementType() == DestTy->getElementType()))
1121 SmallVector<int, 16> NewMask;
1122 if (DestEltSize <= SrcEltSize) {
1125 if (SrcEltSize % DestEltSize != 0)
1127 unsigned ScaleFactor = SrcEltSize / DestEltSize;
1132 if (DestEltSize % SrcEltSize != 0)
1134 unsigned ScaleFactor = DestEltSize / SrcEltSize;
1141 unsigned NumSrcElts = SrcTy->getPrimitiveSizeInBits() / DestEltSize;
1142 auto *NewShuffleTy =
1144 auto *OldShuffleTy =
1146 unsigned NumOps = IsUnary ? 1 : 2;
1156 TargetTransformInfo::CastContextHint::None,
1161 TargetTransformInfo::CastContextHint::None,
1164 LLVM_DEBUG(
dbgs() <<
"Found a bitcasted shuffle: " <<
I <<
"\n OldCost: "
1165 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
1167 if (NewCost > OldCost || !NewCost.
isValid())
1175 replaceValue(
I, *Shuf);
1182bool VectorCombine::scalarizeVPIntrinsic(Instruction &
I) {
1196 if (!ScalarOp0 || !ScalarOp1)
1204 auto IsAllTrueMask = [](
Value *MaskVal) {
1207 return ConstValue->isAllOnesValue();
1221 SmallVector<int>
Mask;
1223 Mask.resize(FVTy->getNumElements(), 0);
1232 Args.push_back(
V->getType());
1233 IntrinsicCostAttributes
Attrs(IntrID, VecTy, Args);
1238 std::optional<unsigned> FunctionalOpcode =
1240 std::optional<Intrinsic::ID> ScalarIntrID = std::nullopt;
1241 if (!FunctionalOpcode) {
1250 IntrinsicCostAttributes
Attrs(*ScalarIntrID, VecTy->getScalarType(), Args);
1260 InstructionCost NewCost = ScalarOpCost + SplatCost + CostToKeepSplats;
1262 LLVM_DEBUG(
dbgs() <<
"Found a VP Intrinsic to scalarize: " << VPI
1265 <<
", Cost of scalarizing:" << NewCost <<
"\n");
1268 if (OldCost < NewCost || !NewCost.
isValid())
1279 bool SafeToSpeculate;
1285 *FunctionalOpcode, &VPI,
nullptr, SQ.
AC, SQ.
DT);
1286 if (!SafeToSpeculate &&
1293 {ScalarOp0, ScalarOp1})
1295 ScalarOp0, ScalarOp1);
1304bool VectorCombine::scalarizeOpOrCmp(Instruction &
I) {
1309 if (!UO && !BO && !CI && !
II)
1317 if (Arg->getType() !=
II->getType() &&
1327 for (User *U :
I.users())
1334 std::optional<uint64_t>
Index;
1336 auto Ops =
II ?
II->args() :
I.operands();
1340 uint64_t InsIdx = 0;
1345 if (OpTy->getElementCount().getKnownMinValue() <= InsIdx)
1351 else if (InsIdx != *Index)
1368 if (!
Index.has_value())
1372 Type *ScalarTy = VecTy->getScalarType();
1373 assert(VecTy->isVectorTy() &&
1376 "Unexpected types for insert element into binop or cmp");
1378 unsigned Opcode =
I.getOpcode();
1386 }
else if (UO || BO) {
1390 IntrinsicCostAttributes ScalarICA(
1391 II->getIntrinsicID(), ScalarTy,
1394 IntrinsicCostAttributes VectorICA(
1395 II->getIntrinsicID(), VecTy,
1402 Value *NewVecC =
nullptr;
1404 NewVecC =
simplifyCmpInst(CI->getPredicate(), VecCs[0], VecCs[1], SQ);
1407 simplifyUnOp(UO->getOpcode(), VecCs[0], UO->getFastMathFlags(), SQ);
1409 NewVecC =
simplifyBinOp(BO->getOpcode(), VecCs[0], VecCs[1], SQ);
1423 for (
auto [Idx,
Op, VecC, Scalar] :
enumerate(
Ops, VecCs, ScalarOps)) {
1425 II->getIntrinsicID(), Idx, &
TTI)))
1428 Instruction::InsertElement, VecTy,
CostKind, *Index, VecC, Scalar);
1429 OldCost += InsertCost;
1430 NewCost += !
Op->hasOneUse() * InsertCost;
1434 if (OldCost < NewCost || !NewCost.
isValid())
1444 ++NumScalarIntrinsic;
1454 Scalar = Builder.
CreateCmp(CI->getPredicate(), ScalarOps[0], ScalarOps[1]);
1460 Scalar->setName(
I.getName() +
".scalar");
1465 ScalarInst->copyIRFlags(&
I);
1468 replaceValue(
I, *Insert);
1475bool VectorCombine::foldExtractedCmps(Instruction &
I) {
1480 if (!BI || !
I.getType()->isIntegerTy(1))
1485 Value *B0 =
I.getOperand(0), *B1 =
I.getOperand(1);
1488 CmpPredicate
P0,
P1;
1500 uint64_t Index0, Index1;
1507 ExtractElementInst *ConvertToShuf = getShuffleExtract(Ext0, Ext1,
CostKind);
1510 assert((ConvertToShuf == Ext0 || ConvertToShuf == Ext1) &&
1511 "Unknown ExtractElementInst");
1516 unsigned CmpOpcode =
1522 if (Index0 >= VecTy->getNumElements() || Index1 >= VecTy->getNumElements())
1534 Ext0Cost + Ext1Cost + CmpCost * 2 +
1540 int CheapIndex = ConvertToShuf == Ext0 ? Index1 : Index0;
1541 int ExpensiveIndex = ConvertToShuf == Ext0 ? Index0 : Index1;
1546 ShufMask[CheapIndex] = ExpensiveIndex;
1551 NewCost += Ext0->
hasOneUse() ? 0 : Ext0Cost;
1552 NewCost += Ext1->
hasOneUse() ? 0 : Ext1Cost;
1557 if (OldCost < NewCost || !NewCost.
isValid())
1567 Value *
LHS = ConvertToShuf == Ext0 ? Shuf : VCmp;
1568 Value *
RHS = ConvertToShuf == Ext0 ? VCmp : Shuf;
1571 replaceValue(
I, *NewExt);
1598bool VectorCombine::foldSelectsFromBitcast(Instruction &
I) {
1605 if (!SrcVecTy || !DstVecTy)
1615 if (SrcEltBits != 32 && SrcEltBits != 64)
1618 if (!DstEltTy->
isIntegerTy() || DstEltBits >= SrcEltBits)
1635 if (!ScalarSelCost.
isValid() || ScalarSelCost == 0)
1638 unsigned MinSelects = (VecSelCost.
getValue() / ScalarSelCost.
getValue()) + 1;
1641 if (!BC->hasNUsesOrMore(MinSelects))
1646 DenseMap<Value *, SmallVector<SelectInst *, 8>> CondToSelects;
1648 for (User *U : BC->users()) {
1653 for (User *ExtUser : Ext->users()) {
1657 Cond->getType()->isIntegerTy(1))
1662 if (CondToSelects.
empty())
1665 bool MadeChange =
false;
1666 Value *SrcVec = BC->getOperand(0);
1669 for (
auto [
Cond, Selects] : CondToSelects) {
1671 if (Selects.size() < MinSelects) {
1672 LLVM_DEBUG(
dbgs() <<
"VectorCombine: foldSelectsFromBitcast not "
1673 <<
"profitable (VecCost=" << VecSelCost
1674 <<
", ScalarCost=" << ScalarSelCost
1675 <<
", NumSelects=" << Selects.size() <<
")\n");
1680 auto InsertPt = std::next(BC->getIterator());
1684 InsertPt = std::next(CondInst->getIterator());
1692 for (SelectInst *Sel : Selects) {
1694 Value *Idx = Ext->getIndexOperand();
1698 replaceValue(*Sel, *NewExt);
1703 <<
" selects into vector select\n");
1717 unsigned ReductionOpc =
1723 CostBeforeReduction =
1724 TTI.getCastInstrCost(RedOp->getOpcode(), VecRedTy, ExtType,
1726 CostAfterReduction =
1727 TTI.getExtendedReductionCost(ReductionOpc, IsUnsigned,
II.getType(),
1731 if (RedOp &&
II.getIntrinsicID() == Intrinsic::vector_reduce_add &&
1737 (Op0->
getOpcode() == RedOp->getOpcode() || Op0 == Op1)) {
1744 TTI.getCastInstrCost(Op0->
getOpcode(), MulType, ExtType,
1747 TTI.getArithmeticInstrCost(Instruction::Mul, MulType,
CostKind);
1749 TTI.getCastInstrCost(RedOp->getOpcode(), VecRedTy, MulType,
1752 CostBeforeReduction = ExtCost * 2 + MulCost + Ext2Cost;
1753 CostAfterReduction =
TTI.getMulAccReductionCost(
1754 IsUnsigned, ReductionOpc,
II.getType(), ExtType,
CostKind);
1757 CostAfterReduction =
TTI.getArithmeticReductionCost(ReductionOpc, VecRedTy,
1761bool VectorCombine::foldBinopOfReductions(Instruction &
I) {
1764 if (BinOpOpc == Instruction::Sub)
1765 ReductionIID = Intrinsic::vector_reduce_add;
1769 if (ReductionIID == Intrinsic::vector_reduce_fadd ||
1770 ReductionIID == Intrinsic::vector_reduce_fmul)
1773 auto checkIntrinsicAndGetItsArgument = [](
Value *
V,
1778 if (
II->getIntrinsicID() == IID &&
II->hasOneUse())
1779 return II->getArgOperand(0);
1783 Value *V0 = checkIntrinsicAndGetItsArgument(
I.getOperand(0), ReductionIID);
1786 Value *
V1 = checkIntrinsicAndGetItsArgument(
I.getOperand(1), ReductionIID);
1791 if (
V1->getType() != VTy)
1795 unsigned ReductionOpc =
1808 CostOfRedOperand0 + CostOfRedOperand1 +
1811 if (NewCost >= OldCost || !NewCost.
isValid())
1815 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
1818 if (BinOpOpc == Instruction::Or)
1825 replaceValue(
I, *Rdx);
1833 unsigned NumScanned = 0;
1834 return std::any_of(Begin, End, [&](
const Instruction &Instr) {
1843class ScalarizationResult {
1844 enum class StatusTy { Unsafe, Safe, SafeWithFreeze };
1849 ScalarizationResult(StatusTy Status,
Value *ToFreeze =
nullptr)
1850 : Status(Status), ToFreeze(ToFreeze) {}
1853 ScalarizationResult(
const ScalarizationResult &
Other) =
default;
1854 ~ScalarizationResult() {
1855 assert(!ToFreeze &&
"freeze() not called with ToFreeze being set");
1858 static ScalarizationResult unsafe() {
return {StatusTy::Unsafe}; }
1859 static ScalarizationResult safe() {
return {StatusTy::Safe}; }
1860 static ScalarizationResult safeWithFreeze(
Value *ToFreeze) {
1861 return {StatusTy::SafeWithFreeze, ToFreeze};
1865 bool isSafe()
const {
return Status == StatusTy::Safe; }
1867 bool isUnsafe()
const {
return Status == StatusTy::Unsafe; }
1870 bool isSafeWithFreeze()
const {
return Status == StatusTy::SafeWithFreeze; }
1875 Status = StatusTy::Unsafe;
1879 void freeze(IRBuilderBase &Builder, Instruction &UserI) {
1880 assert(isSafeWithFreeze() &&
1881 "should only be used when freezing is required");
1883 "UserI must be a user of ToFreeze");
1884 IRBuilder<>::InsertPointGuard Guard(Builder);
1889 if (
U.get() == ToFreeze)
1904 uint64_t NumElements = VecTy->getElementCount().getKnownMinValue();
1908 if (
C->getValue().ult(NumElements))
1909 return ScalarizationResult::safe();
1910 return ScalarizationResult::unsafe();
1915 return ScalarizationResult::unsafe();
1917 APInt Zero(IntWidth, 0);
1918 APInt MaxElts(IntWidth, NumElements);
1925 return ScalarizationResult::safe();
1926 return ScalarizationResult::unsafe();
1939 if (ValidIndices.
contains(IdxRange))
1940 return ScalarizationResult::safeWithFreeze(IdxBase);
1941 return ScalarizationResult::unsafe();
1953 C->getZExtValue() *
DL.getTypeStoreSize(ScalarType));
1965bool VectorCombine::foldSingleElementStore(Instruction &
I) {
1977 if (!
match(
SI->getValueOperand(),
1984 Value *SrcAddr =
Load->getPointerOperand()->stripPointerCasts();
1987 if (!
Load->isSimple() ||
Load->getParent() !=
SI->getParent() ||
1988 !
DL->typeSizeEqualsStoreSize(
Load->getType()->getScalarType()) ||
1989 SrcAddr !=
SI->getPointerOperand()->stripPointerCasts())
1995 auto ScalarizableIdx =
1997 if (ScalarizableIdx.isUnsafe())
2002 Worklist.
push(Load);
2004 if (ScalarizableIdx.isSafeWithFreeze())
2007 SI->getValueOperand()->getType(),
SI->getPointerOperand(),
2008 {ConstantInt::get(Idx->getType(), 0), Idx});
2012 std::max(
SI->getAlign(),
Load->getAlign()), NewElement->
getType(), Idx,
2015 replaceValue(
I, *NSI);
2025bool VectorCombine::scalarizeLoad(Instruction &
I) {
2035 if (!LI->isSimple() || !
DL->typeSizeEqualsStoreSize(VecTy->getScalarType()))
2038 bool AllExtracts =
true;
2039 bool AllBitcasts =
true;
2041 unsigned NumInstChecked = 0;
2046 for (User *U : LI->users()) {
2048 if (!UI || UI->getParent() != LI->getParent())
2053 if (UI->use_empty())
2057 AllExtracts =
false;
2059 AllBitcasts =
false;
2063 for (Instruction &
I :
2064 make_range(std::next(LI->getIterator()), UI->getIterator())) {
2071 LastCheckedInst = UI;
2076 return scalarizeLoadExtract(LI, VecTy, Ptr);
2078 return scalarizeLoadBitcast(LI, VecTy, Ptr);
2083bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
2088 DenseMap<ExtractElementInst *, ScalarizationResult> NeedFreeze;
2091 for (
auto &Pair : NeedFreeze)
2092 Pair.second.discard();
2100 for (User *U : LI->
users()) {
2105 if (ScalarIdx.isUnsafe())
2107 if (ScalarIdx.isSafeWithFreeze()) {
2108 NeedFreeze.try_emplace(UI, ScalarIdx);
2109 ScalarIdx.discard();
2115 Index ?
Index->getZExtValue() : -1);
2123 LLVM_DEBUG(
dbgs() <<
"Found all extractions of a vector load: " << *LI
2124 <<
"\n LoadExtractCost: " << OriginalCost
2125 <<
" vs ScalarizedCost: " << ScalarizedCost <<
"\n");
2127 if (ScalarizedCost >= OriginalCost)
2134 Type *ElemType = VecTy->getElementType();
2137 for (User *U : LI->
users()) {
2139 Value *Idx = EI->getIndexOperand();
2142 auto It = NeedFreeze.find(EI);
2143 if (It != NeedFreeze.end())
2150 Builder.
CreateLoad(ElemType,
GEP, EI->getName() +
".scalar"));
2152 Align ScalarOpAlignment =
2154 NewLoad->setAlignment(ScalarOpAlignment);
2157 size_t Offset = ConstIdx->getZExtValue() *
DL->getTypeStoreSize(ElemType);
2162 replaceValue(*EI, *NewLoad,
false);
2165 FailureGuard.release();
2170bool VectorCombine::scalarizeLoadBitcast(LoadInst *LI, VectorType *VecTy,
2176 Type *TargetScalarType =
nullptr;
2177 unsigned VecBitWidth =
DL->getTypeSizeInBits(VecTy);
2179 for (User *U : LI->
users()) {
2182 Type *DestTy = BC->getDestTy();
2186 unsigned DestBitWidth =
DL->getTypeSizeInBits(DestTy);
2187 if (DestBitWidth != VecBitWidth)
2191 if (!TargetScalarType)
2192 TargetScalarType = DestTy;
2193 else if (TargetScalarType != DestTy)
2201 if (!TargetScalarType)
2209 LLVM_DEBUG(
dbgs() <<
"Found vector load feeding only bitcasts: " << *LI
2210 <<
"\n OriginalCost: " << OriginalCost
2211 <<
" vs ScalarizedCost: " << ScalarizedCost <<
"\n");
2213 if (ScalarizedCost >= OriginalCost)
2224 ScalarLoad->copyMetadata(*LI);
2227 for (User *U : LI->
users()) {
2229 replaceValue(*BC, *ScalarLoad,
false);
2235bool VectorCombine::scalarizeExtExtract(Instruction &
I) {
2250 Type *ScalarDstTy = DstTy->getElementType();
2251 if (
DL->getTypeSizeInBits(SrcTy) !=
DL->getTypeSizeInBits(ScalarDstTy))
2257 unsigned ExtCnt = 0;
2258 bool ExtLane0 =
false;
2259 for (User *U : Ext->users()) {
2273 Instruction::And, ScalarDstTy,
CostKind,
2276 (ExtCnt - ExtLane0) *
2278 Instruction::LShr, ScalarDstTy,
CostKind,
2281 if (ScalarCost > VectorCost)
2284 Value *ScalarV = Ext->getOperand(0);
2291 SmallDenseSet<ConstantInt *, 8> ExtractedLanes;
2292 bool AllExtractsTriggerUB =
true;
2293 ExtractElementInst *LastExtract =
nullptr;
2295 for (User *U : Ext->users()) {
2298 AllExtractsTriggerUB =
false;
2302 if (!LastExtract || LastExtract->
comesBefore(Extract))
2303 LastExtract = Extract;
2305 if (ExtractedLanes.
size() != DstTy->getNumElements() ||
2306 !AllExtractsTriggerUB ||
2314 uint64_t SrcEltSizeInBits =
DL->getTypeSizeInBits(SrcTy->getElementType());
2315 uint64_t TotalBits =
DL->getTypeSizeInBits(SrcTy);
2318 Value *
Mask = ConstantInt::get(PackedTy, EltBitMask);
2319 for (User *U : Ext->users()) {
2325 ? (TotalBits - SrcEltSizeInBits - Idx * SrcEltSizeInBits)
2326 : (Idx * SrcEltSizeInBits);
2329 U->replaceAllUsesWith(
And);
2337bool VectorCombine::foldConcatOfBoolMasks(Instruction &
I) {
2338 Type *Ty =
I.getType();
2343 if (
DL->isBigEndian())
2354 uint64_t ShAmtX = 0;
2362 uint64_t ShAmtY = 0;
2370 if (ShAmtX > ShAmtY) {
2378 uint64_t ShAmtDiff = ShAmtY - ShAmtX;
2379 unsigned NumSHL = (ShAmtX > 0) + (ShAmtY > 0);
2384 MaskTy->getNumElements() != ShAmtDiff ||
2385 MaskTy->getNumElements() > (
BitWidth / 2))
2390 Type::getIntNTy(Ty->
getContext(), ConcatTy->getNumElements());
2391 auto *MaskIntTy = Type::getIntNTy(Ty->
getContext(), ShAmtDiff);
2394 std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
2411 if (Ty != ConcatIntTy)
2417 LLVM_DEBUG(
dbgs() <<
"Found a concatenation of bitcasted bool masks: " <<
I
2418 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2421 if (NewCost > OldCost)
2431 if (Ty != ConcatIntTy) {
2441 replaceValue(
I, *Result);
2447bool VectorCombine::foldPermuteOfBinops(Instruction &
I) {
2448 BinaryOperator *BinOp;
2449 ArrayRef<int> OuterMask;
2457 Value *Op00, *Op01, *Op10, *Op11;
2458 ArrayRef<int> Mask0, Mask1;
2463 if (!Match0 && !Match1)
2476 if (!ShuffleDstTy || !BinOpTy || !Op0Ty || !Op1Ty)
2479 unsigned NumSrcElts = BinOpTy->getNumElements();
2484 any_of(OuterMask, [NumSrcElts](
int M) {
return M >= (int)NumSrcElts; }))
2488 SmallVector<int> NewMask0, NewMask1;
2489 for (
int M : OuterMask) {
2490 if (M < 0 || M >= (
int)NumSrcElts) {
2494 NewMask0.
push_back(Match0 ? Mask0[M] : M);
2495 NewMask1.
push_back(Match1 ? Mask1[M] : M);
2499 unsigned NumOpElts = Op0Ty->getNumElements();
2500 bool IsIdentity0 = ShuffleDstTy == Op0Ty &&
2501 all_of(NewMask0, [NumOpElts](
int M) {
return M < (int)NumOpElts; }) &&
2503 bool IsIdentity1 = ShuffleDstTy == Op1Ty &&
2504 all_of(NewMask1, [NumOpElts](
int M) {
return M < (int)NumOpElts; }) &&
2513 ShuffleDstTy, BinOpTy, OuterMask,
CostKind,
2514 0,
nullptr, {BinOp}, &
I);
2516 NewCost += BinOpCost;
2522 OldCost += Shuf0Cost;
2524 NewCost += Shuf0Cost;
2530 OldCost += Shuf1Cost;
2532 NewCost += Shuf1Cost;
2540 Op0Ty, NewMask0,
CostKind, 0,
nullptr, {Op00, Op01});
2544 Op1Ty, NewMask1,
CostKind, 0,
nullptr, {Op10, Op11});
2546 LLVM_DEBUG(
dbgs() <<
"Found a shuffle feeding a shuffled binop: " <<
I
2547 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2551 if (NewCost > OldCost)
2562 NewInst->copyIRFlags(BinOp);
2566 replaceValue(
I, *NewBO);
2572bool VectorCombine::foldShuffleOfBinops(Instruction &
I) {
2573 ArrayRef<int> OldMask;
2580 if (
LHS->getOpcode() !=
RHS->getOpcode())
2584 bool IsCommutative =
false;
2593 IsCommutative = BinaryOperator::isCommutative(BO->getOpcode());
2604 if (!ShuffleDstTy || !BinResTy || !BinOpTy ||
X->getType() !=
Z->getType())
2607 bool SameBinOp =
LHS ==
RHS;
2608 unsigned NumSrcElts = BinOpTy->getNumElements();
2611 if (IsCommutative &&
X != Z &&
Y != W && (
X == W ||
Y == Z))
2614 auto ConvertToUnary = [NumSrcElts](
int &
M) {
2615 if (M >= (
int)NumSrcElts)
2619 SmallVector<int> NewMask0(OldMask);
2628 SmallVector<int> NewMask1(OldMask);
2647 ShuffleDstTy, BinResTy, OldMask,
CostKind, 0,
2657 ArrayRef<int> InnerMask;
2659 m_Mask(InnerMask)))) &&
2662 [NumSrcElts](
int M) {
return M < (int)NumSrcElts; })) {
2674 bool ReducedInstCount =
false;
2675 ReducedInstCount |= MergeInner(
X, 0, NewMask0,
CostKind);
2676 ReducedInstCount |= MergeInner(
Y, 0, NewMask1,
CostKind);
2677 ReducedInstCount |= MergeInner(Z, NumSrcElts, NewMask0,
CostKind);
2678 ReducedInstCount |= MergeInner(W, NumSrcElts, NewMask1,
CostKind);
2679 bool SingleSrcBinOp = (
X ==
Y) && (Z == W) && (NewMask0 == NewMask1);
2691 I.getType()->getScalarType()->isIntegerTy(1) &&
2695 auto *ShuffleCmpTy =
2698 SK0, ShuffleCmpTy, BinOpTy, NewMask0,
CostKind, 0,
nullptr, {
X,
Z});
2699 if (!SingleSrcBinOp)
2709 PredLHS,
CostKind, Op0Info, Op1Info);
2719 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2726 if (ReducedInstCount ? (NewCost > OldCost) : (NewCost >= OldCost))
2735 : Builder.
CreateCmp(PredLHS, Shuf0, Shuf1);
2739 NewInst->copyIRFlags(
LHS);
2740 NewInst->andIRFlags(
RHS);
2745 replaceValue(
I, *NewBO);
2752bool VectorCombine::foldShuffleOfSelects(Instruction &
I) {
2754 Value *C1, *
T1, *F1, *C2, *T2, *F2;
2765 if (!C1VecTy || !C2VecTy || C1VecTy != C2VecTy)
2771 if (((SI0FOp ==
nullptr) != (SI1FOp ==
nullptr)) ||
2772 ((SI0FOp !=
nullptr) &&
2773 (SI0FOp->getFastMathFlags() != SI1FOp->getFastMathFlags())))
2779 auto SelOp = Instruction::Select;
2787 CostSel1 + CostSel2 +
2789 {
I.getOperand(0),
I.getOperand(1)}, &
I);
2793 Mask,
CostKind, 0,
nullptr, {C1, C2});
2803 if (!Sel1->hasOneUse())
2804 NewCost += CostSel1;
2805 if (!Sel2->hasOneUse())
2806 NewCost += CostSel2;
2809 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2811 if (NewCost > OldCost)
2820 NewSel = Builder.
CreateSelectFMF(ShuffleCmp, ShuffleTrue, ShuffleFalse,
2821 SI0FOp->getFastMathFlags());
2823 NewSel = Builder.
CreateSelect(ShuffleCmp, ShuffleTrue, ShuffleFalse);
2828 replaceValue(
I, *NewSel);
2834bool VectorCombine::foldShuffleOfCastops(Instruction &
I) {
2836 ArrayRef<int> OldMask;
2845 if (!C0 || (IsBinaryShuffle && !C1))
2852 if (!IsBinaryShuffle && Opcode == Instruction::BitCast)
2855 if (IsBinaryShuffle) {
2856 if (C0->getSrcTy() != C1->getSrcTy())
2859 if (Opcode != C1->getOpcode()) {
2861 Opcode = Instruction::SExt;
2870 if (!ShuffleDstTy || !CastDstTy || !CastSrcTy)
2873 unsigned NumSrcElts = CastSrcTy->getNumElements();
2874 unsigned NumDstElts = CastDstTy->getNumElements();
2875 assert((NumDstElts == NumSrcElts || Opcode == Instruction::BitCast) &&
2876 "Only bitcasts expected to alter src/dst element counts");
2880 if (NumDstElts != NumSrcElts && (NumSrcElts % NumDstElts) != 0 &&
2881 (NumDstElts % NumSrcElts) != 0)
2884 SmallVector<int, 16> NewMask;
2885 if (NumSrcElts >= NumDstElts) {
2888 assert(NumSrcElts % NumDstElts == 0 &&
"Unexpected shuffle mask");
2889 unsigned ScaleFactor = NumSrcElts / NumDstElts;
2894 assert(NumDstElts % NumSrcElts == 0 &&
"Unexpected shuffle mask");
2895 unsigned ScaleFactor = NumDstElts / NumSrcElts;
2900 auto *NewShuffleDstTy =
2909 if (IsBinaryShuffle)
2924 if (IsBinaryShuffle) {
2934 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2936 if (NewCost > OldCost)
2940 if (IsBinaryShuffle)
2950 NewInst->copyIRFlags(C0);
2951 if (IsBinaryShuffle)
2952 NewInst->andIRFlags(C1);
2956 replaceValue(
I, *Cast);
2966bool VectorCombine::foldShuffleOfShuffles(Instruction &
I) {
2967 ArrayRef<int> OuterMask;
2968 Value *OuterV0, *OuterV1;
2973 ArrayRef<int> InnerMask0, InnerMask1;
2974 Value *X0, *X1, *Y0, *Y1;
2979 if (!Match0 && !Match1)
2984 SmallVector<int, 16> PoisonMask1;
2989 InnerMask1 = PoisonMask1;
2993 X0 = Match0 ? X0 : OuterV0;
2994 Y0 = Match0 ? Y0 : OuterV0;
2995 X1 = Match1 ? X1 : OuterV1;
2996 Y1 = Match1 ? Y1 : OuterV1;
3000 if (!ShuffleDstTy || !ShuffleSrcTy || !ShuffleImmTy ||
3004 unsigned NumSrcElts = ShuffleSrcTy->getNumElements();
3005 unsigned NumImmElts = ShuffleImmTy->getNumElements();
3010 SmallVector<int, 16> NewMask(OuterMask);
3011 Value *NewX =
nullptr, *NewY =
nullptr;
3012 for (
int &M : NewMask) {
3013 Value *Src =
nullptr;
3014 if (0 <= M && M < (
int)NumImmElts) {
3018 Src =
M >= (int)NumSrcElts ? Y0 : X0;
3019 M =
M >= (int)NumSrcElts ? (M - NumSrcElts) :
M;
3021 }
else if (M >= (
int)NumImmElts) {
3026 Src =
M >= (int)NumSrcElts ? Y1 : X1;
3027 M =
M >= (int)NumSrcElts ? (M - NumSrcElts) :
M;
3031 assert(0 <= M && M < (
int)NumSrcElts &&
"Unexpected shuffle mask index");
3040 if (!NewX || NewX == Src) {
3044 if (!NewY || NewY == Src) {
3063 replaceValue(
I, *NewX);
3080 bool IsUnary =
all_of(NewMask, [&](
int M) {
return M < (int)NumSrcElts; });
3086 nullptr, {NewX, NewY});
3088 NewCost += InnerCost0;
3090 NewCost += InnerCost1;
3093 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
3095 if (NewCost > OldCost)
3099 replaceValue(
I, *Shuf);
3115bool VectorCombine::foldShufflesOfLengthChangingShuffles(Instruction &
I) {
3120 unsigned ChainLength = 0;
3121 SmallVector<int>
Mask;
3122 SmallVector<int> YMask;
3132 ArrayRef<int> OuterMask;
3133 Value *OuterV0, *OuterV1;
3134 if (ChainLength != 0 && !Trunk->
hasOneUse())
3137 m_Mask(OuterMask))))
3139 if (OuterV0->
getType() != TrunkType) {
3145 ArrayRef<int> InnerMask0, InnerMask1;
3146 Value *A0, *A1, *B0, *B1;
3151 bool Match0Leaf = Match0 && A0->
getType() !=
I.getType();
3152 bool Match1Leaf = Match1 && A1->
getType() !=
I.getType();
3153 if (Match0Leaf == Match1Leaf) {
3159 SmallVector<int> CommutedOuterMask;
3166 for (
int &M : CommutedOuterMask) {
3169 if (M < (
int)NumTrunkElts)
3174 OuterMask = CommutedOuterMask;
3193 int NumLeafElts = YType->getNumElements();
3194 SmallVector<int> LocalYMask(InnerMask1);
3195 for (
int &M : LocalYMask) {
3196 if (M >= NumLeafElts)
3206 Mask.assign(OuterMask);
3207 YMask.
assign(LocalYMask);
3208 OldCost = NewCost = LocalOldCost;
3215 SmallVector<int> NewYMask(YMask);
3217 for (
auto [CombinedM, LeafM] :
llvm::zip(NewYMask, LocalYMask)) {
3218 if (LeafM == -1 || CombinedM == LeafM)
3220 if (CombinedM == -1) {
3230 SmallVector<int> NewMask;
3231 NewMask.
reserve(NumTrunkElts);
3232 for (
int M : Mask) {
3233 if (M < 0 || M >=
static_cast<int>(NumTrunkElts))
3248 if (LocalNewCost >= NewCost && LocalOldCost < LocalNewCost - NewCost)
3252 if (ChainLength == 1) {
3253 dbgs() <<
"Found chain of shuffles fed by length-changing shuffles: "
3256 dbgs() <<
" next chain link: " << *Trunk <<
'\n'
3257 <<
" old cost: " << (OldCost + LocalOldCost)
3258 <<
" new cost: " << LocalNewCost <<
'\n';
3263 OldCost += LocalOldCost;
3264 NewCost = LocalNewCost;
3268 if (ChainLength <= 1)
3276 return M < 0 || M >=
static_cast<int>(NumTrunkElts);
3279 for (
int &M : Mask) {
3280 if (M >=
static_cast<int>(NumTrunkElts))
3281 M = YMask[
M - NumTrunkElts];
3285 replaceValue(
I, *Root);
3292 replaceValue(
I, *Root);
3298bool VectorCombine::foldShuffleOfIntrinsics(Instruction &
I) {
3300 ArrayRef<int> OldMask;
3310 if (IID != II1->getIntrinsicID())
3319 if (!ShuffleDstTy || !II0Ty)
3325 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3326 Value *Arg0 = II0->getArgOperand(
I);
3327 Value *Arg1 = II1->getArgOperand(
I);
3344 II0Ty, OldMask,
CostKind, 0,
nullptr, {II0, II1}, &
I);
3348 SmallDenseSet<std::pair<Value *, Value *>> SeenOperandPairs;
3349 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3351 NewArgsTy.
push_back(II0->getArgOperand(
I)->getType());
3355 ShuffleDstTy->getNumElements());
3357 std::pair<Value *, Value *> OperandPair =
3358 std::make_pair(II0->getArgOperand(
I), II1->getArgOperand(
I));
3359 if (!SeenOperandPairs.
insert(OperandPair).second) {
3365 CostKind, 0,
nullptr, {II0->getArgOperand(
I), II1->getArgOperand(
I)});
3368 IntrinsicCostAttributes NewAttr(IID, ShuffleDstTy, NewArgsTy);
3371 if (!II0->hasOneUse())
3373 if (II1 != II0 && !II1->hasOneUse())
3377 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
3380 if (NewCost > OldCost)
3384 SmallDenseMap<std::pair<Value *, Value *>,
Value *> ShuffleCache;
3385 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I)
3389 std::pair<Value *, Value *> OperandPair =
3390 std::make_pair(II0->getArgOperand(
I), II1->getArgOperand(
I));
3391 auto It = ShuffleCache.
find(OperandPair);
3392 if (It != ShuffleCache.
end()) {
3398 II1->getArgOperand(
I), OldMask);
3399 ShuffleCache[OperandPair] = Shuf;
3407 NewInst->copyIRFlags(II0);
3408 NewInst->andIRFlags(II1);
3411 replaceValue(
I, *NewIntrinsic);
3417bool VectorCombine::foldPermuteOfIntrinsic(Instruction &
I) {
3429 if (!ShuffleDstTy || !IntrinsicSrcTy)
3433 unsigned NumSrcElts = IntrinsicSrcTy->getNumElements();
3434 if (
any_of(Mask, [NumSrcElts](
int M) {
return M >= (int)NumSrcElts; }))
3447 IntrinsicSrcTy, Mask,
CostKind, 0,
nullptr, {V0}, &
I);
3451 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3453 NewArgsTy.
push_back(II0->getArgOperand(
I)->getType());
3457 ShuffleDstTy->getNumElements());
3460 ArgTy, VecTy, Mask,
CostKind, 0,
nullptr,
3461 {II0->getArgOperand(
I)});
3464 IntrinsicCostAttributes NewAttr(IID, ShuffleDstTy, NewArgsTy);
3469 if (!II0->hasOneUse())
3472 LLVM_DEBUG(
dbgs() <<
"Found a permute of intrinsic: " <<
I <<
"\n OldCost: "
3473 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
3475 if (NewCost > OldCost)
3480 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3493 NewInst->copyIRFlags(II0);
3495 replaceValue(
I, *NewIntrinsic);
3505 int M = SV->getMaskValue(Lane);
3508 if (
static_cast<unsigned>(M) < NumElts) {
3509 V = SV->getOperand(0);
3512 V = SV->getOperand(1);
3523 auto [U, Lane] = IL;
3536 unsigned NumElts = Ty->getNumElements();
3537 if (Item.
size() == NumElts || NumElts == 1 || Item.
size() % NumElts != 0)
3543 std::iota(ConcatMask.
begin(), ConcatMask.
end(), 0);
3549 unsigned NumSlices = Item.
size() / NumElts;
3554 for (
unsigned Slice = 0; Slice < NumSlices; ++Slice) {
3555 Value *SliceV = Item[Slice * NumElts].first;
3556 if (!SliceV || SliceV->
getType() != Ty)
3558 for (
unsigned Elt = 0; Elt < NumElts; ++Elt) {
3559 auto [V, Lane] = Item[Slice * NumElts + Elt];
3560 if (Lane !=
static_cast<int>(Elt) || SliceV != V)
3569 const DenseSet<std::pair<Value *, Use *>> &IdentityLeafs,
3570 const DenseSet<std::pair<Value *, Use *>> &SplatLeafs,
3571 const DenseSet<std::pair<Value *, Use *>> &ConcatLeafs,
3573 auto [FrontV, FrontLane] = Item.
front();
3575 if (IdentityLeafs.contains(std::make_pair(FrontV, From))) {
3578 if (SplatLeafs.contains(std::make_pair(FrontV, From))) {
3580 return Builder.CreateShuffleVector(FrontV, Mask);
3582 if (ConcatLeafs.contains(std::make_pair(FrontV, From))) {
3586 for (
unsigned S = 0; S <
Values.size(); ++S)
3587 Values[S] = Item[S * NumElts].first;
3589 while (
Values.size() > 1) {
3592 std::iota(Mask.begin(), Mask.end(), 0);
3594 for (
unsigned S = 0; S < NewValues.
size(); ++S)
3596 Builder.CreateShuffleVector(
Values[S * 2],
Values[S * 2 + 1], Mask);
3610 if (BCDstTy && BCSrcTy &&
3611 BCDstTy->getElementCount() != BCSrcTy->getElementCount()) {
3612 unsigned DstElts = BCDstTy->getNumElements();
3613 unsigned SrcElts = BCSrcTy->getNumElements();
3615 if (DstElts > SrcElts) {
3617 unsigned R = DstElts / SrcElts;
3618 if (Item.
size() % R != 0)
3620 for (
unsigned Idx = 0,
E = Item.
size(); Idx <
E; Idx += R) {
3621 auto [V, Lane] = Item[Idx];
3631 unsigned R = SrcElts / DstElts;
3632 for (
auto [V, Lane] : Item) {
3638 for (
unsigned J = 0; J < R; ++J)
3643 IdentityLeafs, SplatLeafs, ConcatLeafs,
3645 return Builder.CreateBitCast(
3650 unsigned NumOps =
I->getNumOperands() - (
II ? 1 : 0);
3652 for (
unsigned Idx = 0; Idx <
NumOps; Idx++) {
3655 Ops[Idx] =
II->getOperand(Idx);
3659 &
I->getOperandUse(Idx), IdentityLeafs,
3660 SplatLeafs, ConcatLeafs, Builder,
TTI);
3664 for (
const auto &Lane : Item)
3677 auto *
Value = Builder.CreateCmp(CI->getPredicate(),
Ops[0],
Ops[1]);
3687 auto *
Value = Builder.CreateCast(CI->getOpcode(),
Ops[0], DstTy);
3692 auto *
Value = Builder.CreateIntrinsic(DstTy,
II->getIntrinsicID(),
Ops);
3706bool VectorCombine::foldShuffleToIdentity(Instruction &
I) {
3708 if (!Ty ||
I.use_empty())
3712 for (
unsigned M = 0,
E = Ty->getNumElements(); M <
E; ++M)
3716 Worklist.
push_back(std::make_pair(Start, &*
I.use_begin()));
3717 DenseSet<std::pair<Value *, Use *>> IdentityLeafs, SplatLeafs, ConcatLeafs;
3718 unsigned NumVisited = 0;
3719 bool TraversedElCountChangingBitcast =
false;
3721 while (!Worklist.
empty()) {
3726 auto Item = ItemFrom.first;
3727 auto From = ItemFrom.second;
3728 auto [FrontV, FrontLane] = Item.front();
3736 return X->getType() ==
Y->getType() &&
3741 if (FrontLane == 0 &&
3745 Value *FrontV = Item.front().first;
3746 return !
E.value().first || (IsEquiv(
E.value().first, FrontV) &&
3747 E.value().second == (int)
E.index());
3749 IdentityLeafs.
insert(std::make_pair(FrontV, From));
3754 C &&
C->getSplatValue() &&
3756 Value *FrontV = Item.front().first;
3762 SplatLeafs.
insert(std::make_pair(FrontV, From));
3767 auto [FrontV, FrontLane] = Item.front();
3768 auto [
V, Lane] = IL;
3769 return !
V || (
V == FrontV && Lane == FrontLane);
3771 SplatLeafs.
insert(std::make_pair(FrontV, From));
3777 auto CheckLaneIsEquivalentToFirst = [Item](
InstLane IL) {
3778 Value *FrontV = Item.front().first;
3787 if (CI->getPredicate() !=
cast<CmpInst>(FrontV)->getPredicate())
3790 if (CI->getSrcTy()->getScalarType() !=
3795 SI->getOperand(0)->getType() !=
3802 II->getIntrinsicID() ==
3804 !
II->hasOperandBundles());
3811 BO && BO->isIntDivRem())
3818 }
else if (
isa<UnaryOperator, TruncInst, ZExtInst, SExtInst, FPToSIInst,
3819 FPToUIInst, SIToFPInst, UIToFPInst>(FrontV)) {
3826 if (BCDstTy && BCSrcTy) {
3827 ElementCount DstEC = BCDstTy->getElementCount();
3828 ElementCount SrcEC = BCSrcTy->getElementCount();
3829 if (DstEC == SrcEC) {
3832 &BitCast->getOperandUse(0));
3837 if (DstElts > SrcElts && DstElts % SrcElts == 0) {
3841 unsigned R = DstElts / SrcElts;
3843 bool Valid = Item.size() %
R == 0;
3844 for (
unsigned Idx = 0,
E = Item.size(); Valid && Idx <
E;
3846 auto [V0, L0] = Item[Idx];
3849 [](
InstLane IL) {
return IL.first !=
nullptr; })) {
3860 for (
unsigned J = 1; J <
R; ++J) {
3861 auto [VJ, LJ] = Item[Idx + J];
3862 if (!VJ || VJ != V0 || LJ != L0 + (
int)J) {
3873 TraversedElCountChangingBitcast =
true;
3874 Worklist.
emplace_back(NItem, &BitCast->getOperandUse(0));
3877 }
else if (SrcElts > DstElts && SrcElts % DstElts == 0) {
3880 unsigned R = SrcElts / DstElts;
3882 for (
auto [V, Lane] : Item) {
3888 for (
unsigned J = 0; J <
R; ++J)
3891 TraversedElCountChangingBitcast =
true;
3892 Worklist.
emplace_back(NItem, &BitCast->getOperandUse(0));
3898 &Sel->getOperandUse(0));
3900 &Sel->getOperandUse(1));
3902 &Sel->getOperandUse(2));
3906 !
II->hasOperandBundles()) {
3907 for (
unsigned Op = 0,
E =
II->getNumOperands() - 1;
Op <
E;
Op++) {
3911 Value *FrontV = Item.front().first;
3927 ConcatLeafs.
insert(std::make_pair(FrontV, From));
3934 if (NumVisited <= 1)
3940 if (NumVisited == 2 && TraversedElCountChangingBitcast)
3943 LLVM_DEBUG(
dbgs() <<
"Found a superfluous identity shuffle: " <<
I <<
"\n");
3949 SplatLeafs, ConcatLeafs, Builder, &
TTI);
3950 replaceValue(
I, *V);
3957bool VectorCombine::foldShuffleFromReductions(Instruction &
I) {
3961 switch (
II->getIntrinsicID()) {
3962 case Intrinsic::vector_reduce_add:
3963 case Intrinsic::vector_reduce_mul:
3964 case Intrinsic::vector_reduce_and:
3965 case Intrinsic::vector_reduce_or:
3966 case Intrinsic::vector_reduce_xor:
3967 case Intrinsic::vector_reduce_smin:
3968 case Intrinsic::vector_reduce_smax:
3969 case Intrinsic::vector_reduce_umin:
3970 case Intrinsic::vector_reduce_umax:
3979 std::queue<Value *> Worklist;
3980 SmallPtrSet<Value *, 4> Visited;
3981 ShuffleVectorInst *Shuffle =
nullptr;
3985 while (!Worklist.empty()) {
3986 Value *CV = Worklist.front();
3998 if (CI->isBinaryOp()) {
3999 for (
auto *
Op : CI->operand_values())
4003 if (Shuffle && Shuffle != SV)
4020 for (
auto *V : Visited)
4021 for (
auto *U :
V->users())
4022 if (!Visited.contains(U) && U != &
I)
4025 FixedVectorType *VecType =
4029 FixedVectorType *ShuffleInputType =
4031 if (!ShuffleInputType)
4037 SmallVector<int> ConcatMask;
4039 sort(ConcatMask, [](
int X,
int Y) {
return (
unsigned)
X < (unsigned)
Y; });
4040 bool UsesSecondVec =
4041 any_of(ConcatMask, [&](
int M) {
return M >= (int)NumInputElts; });
4048 ShuffleInputType, ConcatMask,
CostKind);
4050 LLVM_DEBUG(
dbgs() <<
"Found a reduction feeding from a shuffle: " << *Shuffle
4052 LLVM_DEBUG(
dbgs() <<
" OldCost: " << OldCost <<
" vs NewCost: " << NewCost
4054 bool MadeChanges =
false;
4055 if (NewCost < OldCost) {
4059 LLVM_DEBUG(
dbgs() <<
"Created new shuffle: " << *NewShuffle <<
"\n");
4060 replaceValue(*Shuffle, *NewShuffle);
4066 MadeChanges |= foldSelectShuffle(*Shuffle,
true);
4087bool VectorCombine::foldShuffleChainsToReduce(Instruction &
I) {
4096 if (FVT->getNumElements() < 2)
4099 std::optional<Instruction::BinaryOps> CommonBinOp;
4100 std::optional<Intrinsic::ID> CommonCallOp;
4105 CommonBinOp = BO->getOpcode();
4107 CommonCallOp = MMI->getIntrinsicID();
4113 FastMathFlags CommonFMF;
4114 bool IsFloatReduction =
false;
4118 auto IsChainNode = [&](
Value *
V) {
4120 return CommonBinOp && BO->getOpcode() == *CommonBinOp;
4122 return CommonCallOp && MMI->getIntrinsicID() == *CommonCallOp;
4130 constexpr unsigned MaxChainNodes = 32;
4131 SmallSetVector<Value *, 16> Nodes;
4132 SmallSetVector<Value *, 4> Sources;
4133 unsigned NumVisited = 0;
4134 auto AddSource = [&](
Value *
V) {
4140 auto Walk = [&](
Value *
V,
auto &&Walk) ->
bool {
4143 if (++NumVisited > MaxChainNodes)
4145 if (!IsChainNode(V))
4146 return AddSource(V);
4151 if (!Walk(
U->getOperand(
I), Walk))
4160 return AddSource(V);
4162 if (!Walk(VecOpEE, Walk) || Nodes.
empty())
4169 for (
Value *V : Nodes) {
4175 if (!IsFloatReduction) {
4177 IsFloatReduction =
true;
4191 DenseMap<Value *, Demand> Demands;
4192 auto DemandOf = [&](
Value *
V) -> Demand & {
4194 Demand &
D = Demands[
V];
4195 if (
D.Lanes.getBitWidth() !=
N)
4199 DemandOf(VecOpEE).Lanes.setBit(0);
4201 Demand DV = Demands.
lookup(V);
4202 if (DV.Lanes.isZero())
4205 ArrayRef<int>
Mask = SVI->getShuffleMask();
4206 Demand &
DS = DemandOf(SVI->getOperand(0));
4207 for (
unsigned I = 0,
E =
Mask.size();
I !=
E; ++
I) {
4209 if (!DV.Lanes[
I] || Mask[
I] < 0 ||
4210 (
unsigned)Mask[
I] >=
DS.Lanes.getBitWidth())
4212 if (
DS.Lanes[Mask[
I]] || DV.Duplicates[
I])
4213 DS.Duplicates.setBit(Mask[
I]);
4214 DS.Lanes.setBit(Mask[
I]);
4218 for (
Value *
Op : {
U->getOperand(0),
U->getOperand(1)}) {
4219 Demand &DOp = DemandOf(
Op);
4221 DOp.Duplicates |= DV.Duplicates | (DOp.Lanes & DV.Lanes);
4222 DOp.Lanes |= DV.Lanes;
4229 auto CoversChain = [&](
Value *
V) {
4230 SmallVector<Value *, 8> Worklist(1, VecOpEE);
4231 SmallPtrSet<Value *, 8> Seen;
4233 while (!Worklist.empty()) {
4236 for (
unsigned I = 0;
I !=
NumOps; ++
I) {
4240 if (!Nodes.contains(
Op))
4242 Worklist.push_back(
Op);
4250 struct ReductionCut {
4254 std::optional<ReductionCut> Cut;
4255 for (
Value *S : Sources) {
4256 auto It = Demands.
find(S);
4257 if (It == Demands.
end() || It->second.Lanes.isZero())
4259 if (Cut || (!IsIdempotent && !It->second.Duplicates.isZero())) {
4263 Cut = ReductionCut{S, It->second.Lanes};
4266 for (
Value *V : Nodes) {
4269 auto It = Demands.
find(V);
4270 if (It == Demands.
end() || !It->second.Lanes.isAllOnes())
4272 if (!IsIdempotent && !It->second.Duplicates.isZero())
4274 if (!CoversChain(V))
4276 Cut = ReductionCut{
V, It->second.Lanes};
4281 if (!Cut || Cut->Elts.popcount() < 2)
4291 for (
Value *V : Nodes)
4295 bool IsPartialReduction = !Cut->Elts.isAllOnes();
4296 FixedVectorType *ReduceVecTy =
4301 SmallVector<int> ExtractMask;
4303 if (IsPartialReduction) {
4304 for (
unsigned I = 0,
E = Cut->Elts.getBitWidth();
I !=
E; ++
I)
4306 ExtractMask.push_back(
I);
4307 unsigned SubIdx = 0, SubLen;
4308 auto SK = Cut->Elts.isShiftedMask(SubIdx, SubLen)
4312 SubIdx, ReduceVecTy);
4315 IntrinsicCostAttributes ICA(
4316 ReducedOp, ReduceVecTy->getElementType(),
4320 IsFloatReduction ? CommonFMF : FastMathFlags());
4323 LLVM_DEBUG(
dbgs() <<
"Found reduction shuffle chain: " <<
I <<
"\n OldCost : "
4324 << OrigCost <<
" vs NewCost: " << NewCost <<
"\n");
4329 if (VecOpEE->
hasOneUse() ? (NewCost > OrigCost) : (NewCost >= OrigCost))
4332 Value *ReduceInput = Cut->Src;
4333 if (IsPartialReduction)
4336 Value *ReducedResult;
4337 if (IsFloatReduction) {
4339 *CommonBinOp, ReduceVecTy->getElementType(),
false,
4342 {Identity, ReduceInput}, CommonFMF);
4347 replaceValue(
I, *ReducedResult);
4356bool VectorCombine::foldCastFromReductions(Instruction &
I) {
4361 bool TruncOnly =
false;
4364 case Intrinsic::vector_reduce_add:
4365 case Intrinsic::vector_reduce_mul:
4368 case Intrinsic::vector_reduce_and:
4369 case Intrinsic::vector_reduce_or:
4370 case Intrinsic::vector_reduce_xor:
4377 Value *ReductionSrc =
I.getOperand(0);
4389 Type *ResultTy =
I.getType();
4392 ReductionOpc, ReductionSrcTy, std::nullopt,
CostKind);
4402 if (OldCost <= NewCost || !NewCost.
isValid())
4406 II->getIntrinsicID(), {Src});
4408 replaceValue(
I, *NewCast);
4436bool VectorCombine::foldSignBitReductionCmp(Instruction &
I) {
4438 IntrinsicInst *ReduceOp;
4439 const APInt *CmpVal;
4446 case Intrinsic::vector_reduce_or:
4447 case Intrinsic::vector_reduce_umax:
4448 case Intrinsic::vector_reduce_and:
4449 case Intrinsic::vector_reduce_umin:
4450 case Intrinsic::vector_reduce_add:
4461 unsigned BitWidth = VecTy->getScalarSizeInBits();
4465 unsigned NumElts = VecTy->getNumElements();
4474 case Intrinsic::vector_reduce_or:
4475 case Intrinsic::vector_reduce_umax:
4476 TreeOpcode = Instruction::Or;
4478 case Intrinsic::vector_reduce_and:
4479 case Intrinsic::vector_reduce_umin:
4480 TreeOpcode = Instruction::And;
4482 case Intrinsic::vector_reduce_add:
4483 TreeOpcode = Instruction::Add;
4491 SmallVector<Value *, 8> Worklist;
4492 SmallVector<Value *, 8> Sources;
4494 std::optional<bool> IsAShr;
4495 constexpr unsigned MaxSources = 8;
4500 while (!Worklist.
empty() && Worklist.
size() <= MaxSources &&
4501 Sources.
size() <= MaxSources) {
4510 bool ThisIsAShr = Shr->getOpcode() == Instruction::AShr;
4512 IsAShr = ThisIsAShr;
4513 else if (*IsAShr != ThisIsAShr)
4539 if (Sources.
empty() || Sources.
size() > MaxSources ||
4540 Worklist.
size() > MaxSources || !IsAShr)
4543 unsigned NumSources = Sources.
size();
4547 if (OrigIID == Intrinsic::vector_reduce_add &&
4555 (OrigIID == Intrinsic::vector_reduce_add) ? NumSources * NumElts : 1;
4558 NegativeVal.negate();
4590 TestsNegative =
false;
4591 }
else if (*CmpVal == NegativeVal) {
4592 TestsNegative =
true;
4596 IsEq = Pred == ICmpInst::ICMP_EQ;
4597 }
else if (Pred == ICmpInst::ICMP_SLT && *CmpVal == RangeHigh) {
4599 TestsNegative = (RangeHigh == NegativeVal);
4600 }
else if (Pred == ICmpInst::ICMP_SGT && *CmpVal == RangeHigh - 1) {
4602 TestsNegative = (RangeHigh == NegativeVal);
4603 }
else if (Pred == ICmpInst::ICMP_SGT && *CmpVal == RangeLow) {
4605 TestsNegative = (RangeLow == NegativeVal);
4606 }
else if (Pred == ICmpInst::ICMP_SLT && *CmpVal == RangeLow + 1) {
4608 TestsNegative = (RangeLow == NegativeVal);
4651 enum CheckKind :
unsigned {
4658 auto RequiresOr = [](CheckKind
C) ->
bool {
return C & 0b100; };
4660 auto IsNegativeCheck = [](CheckKind
C) ->
bool {
return C & 0b010; };
4662 auto Invert = [](CheckKind
C) {
return CheckKind(
C ^ 0b011); };
4666 case Intrinsic::vector_reduce_or:
4667 case Intrinsic::vector_reduce_umax:
4668 Base = TestsNegative ? AnyNeg : AllNonNeg;
4670 case Intrinsic::vector_reduce_and:
4671 case Intrinsic::vector_reduce_umin:
4672 Base = TestsNegative ? AllNeg : AnyNonNeg;
4674 case Intrinsic::vector_reduce_add:
4675 Base = TestsNegative ? AllNeg : AllNonNeg;
4690 return ArithCost <= MinMaxCost ? std::make_pair(Arith, ArithCost)
4691 : std::make_pair(MinMax, MinMaxCost);
4695 auto [NewIID, NewCost] = RequiresOr(
Check)
4696 ? PickCheaper(Intrinsic::vector_reduce_or,
4697 Intrinsic::vector_reduce_umax)
4698 : PickCheaper(
Intrinsic::vector_reduce_and,
4702 if (NumSources > 1) {
4703 unsigned CombineOpc =
4704 RequiresOr(
Check) ? Instruction::Or : Instruction::And;
4709 LLVM_DEBUG(
dbgs() <<
"Found sign-bit reduction cmp: " <<
I <<
"\n OldCost: "
4710 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
4712 if (NewCost > OldCost)
4717 Type *ScalarTy = VecTy->getScalarType();
4720 if (NumSources == 1) {
4731 replaceValue(
I, *NewCmp);
4762bool VectorCombine::foldReductionZeroTest(Instruction &
I) {
4771 if (!
II || !
II->hasOneUse())
4774 auto ReduceID =
II->getIntrinsicID();
4775 if (ReduceID != Intrinsic::vector_reduce_or &&
4776 ReduceID != Intrinsic::vector_reduce_umax)
4779 Value *Vec =
II->getArgOperand(0);
4781 if (!VecTy || !VecTy->getElementType()->isIntegerTy())
4786 ? Intrinsic::vector_reduce_or
4801 LLVM_DEBUG(
dbgs() <<
"Found a reduction zero test: " <<
I <<
"\n OldCost: "
4802 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
4804 if (!OldCost.
isValid() || !NewCost.
isValid() || NewCost > OldCost)
4810 replaceValue(
I, *NewReduce);
4835bool VectorCombine::foldICmpEqZeroVectorReduce(Instruction &
I) {
4846 switch (
II->getIntrinsicID()) {
4847 case Intrinsic::vector_reduce_add:
4848 case Intrinsic::vector_reduce_or:
4849 case Intrinsic::vector_reduce_umin:
4850 case Intrinsic::vector_reduce_umax:
4851 case Intrinsic::vector_reduce_smin:
4852 case Intrinsic::vector_reduce_smax:
4858 Value *InnerOp =
II->getArgOperand(0);
4901 switch (
II->getIntrinsicID()) {
4902 case Intrinsic::vector_reduce_add: {
4907 unsigned NumElems = XTy->getNumElements();
4913 if (LeadingZerosX <= LostBits || LeadingZerosFX <= LostBits)
4921 case Intrinsic::vector_reduce_smin:
4922 case Intrinsic::vector_reduce_smax:
4932 LLVM_DEBUG(
dbgs() <<
"Found a reduction to 0 comparison with removable op: "
4948 case Intrinsic::vector_reduce_add:
4949 case Intrinsic::vector_reduce_or:
4955 case Intrinsic::vector_reduce_umin:
4956 case Intrinsic::vector_reduce_umax:
4957 case Intrinsic::vector_reduce_smin:
4958 case Intrinsic::vector_reduce_smax:
4970 NewReduceCost + (InnerOp->
hasOneUse() ? 0 : ExtCost);
4972 LLVM_DEBUG(
dbgs() <<
"Found a removable extension before reduction: "
4973 << *InnerOp <<
"\n OldCost: " << OldCost
4974 <<
" vs NewCost: " << NewCost <<
"\n");
4980 if (NewCost > OldCost)
4989 Builder.
CreateICmp(Pred, NewReduce, ConstantInt::getNullValue(Ty));
4990 replaceValue(
I, *NewCmp);
5021bool VectorCombine::foldEquivalentReductionCmp(Instruction &
I) {
5024 const APInt *CmpVal;
5029 if (!
II || !
II->hasOneUse())
5032 const auto IsValidOrUmaxCmp = [&]() {
5041 bool IsPositive = CmpVal->
isAllOnes() && Pred == ICmpInst::ICMP_SGT;
5043 bool IsNegative = (CmpVal->
isZero() || CmpVal->
isOne() || *CmpVal == 2) &&
5044 Pred == ICmpInst::ICMP_SLT;
5045 return IsEquality || IsPositive || IsNegative;
5048 const auto IsValidAndUminCmp = [&]() {
5053 const auto LeadingOnes = CmpVal->
countl_one();
5060 bool IsNegative = CmpVal->
isZero() && Pred == ICmpInst::ICMP_SLT;
5069 ((*CmpVal)[0] || (*CmpVal)[1]) && Pred == ICmpInst::ICMP_SGT;
5070 return IsEquality || IsNegative || IsPositive;
5078 switch (OriginalIID) {
5079 case Intrinsic::vector_reduce_or:
5080 if (!IsValidOrUmaxCmp())
5082 AlternativeIID = Intrinsic::vector_reduce_umax;
5084 case Intrinsic::vector_reduce_umax:
5085 if (!IsValidOrUmaxCmp())
5087 AlternativeIID = Intrinsic::vector_reduce_or;
5089 case Intrinsic::vector_reduce_and:
5090 if (!IsValidAndUminCmp())
5092 AlternativeIID = Intrinsic::vector_reduce_umin;
5094 case Intrinsic::vector_reduce_umin:
5095 if (!IsValidAndUminCmp())
5097 AlternativeIID = Intrinsic::vector_reduce_and;
5110 if (ReductionOpc != Instruction::ICmp)
5121 <<
"\n OrigCost: " << OrigCost
5122 <<
" vs AltCost: " << AltCost <<
"\n");
5124 if (AltCost >= OrigCost)
5128 Type *ScalarTy = VecTy->getScalarType();
5131 Builder.
CreateICmp(Pred, NewReduce, ConstantInt::get(ScalarTy, *CmpVal));
5133 replaceValue(
I, *NewCmp);
5147 unsigned Depth = 0) {
5148 constexpr unsigned MaxLocalDepth = 2;
5149 if (
Depth > MaxLocalDepth)
5152 auto NumSignBits = [&](
const Value *
X) {
5155 if (NumSignBits(V) == V->getType()->getScalarSizeInBits())
5160 return NumSignBits(
A) >= 2 && NumSignBits(
B) >= 2 &&
5171bool VectorCombine::foldReduceAddCmpZero(Instruction &
I) {
5181 if (!VecTy || VecTy->getNumElements() < 2)
5187 if (!IsNonNegative && !IsNonPositive)
5192 unsigned NumElts = VecTy->getNumElements();
5194 if (
Log2_32(NumElts) >= NumSignBits)
5197 ICmpInst::Predicate NewPred;
5199 case ICmpInst::ICMP_EQ:
5200 case ICmpInst::ICMP_ULE:
5201 case ICmpInst::ICMP_SLE:
5202 case ICmpInst::ICMP_SGE:
5203 NewPred = ICmpInst::ICMP_EQ;
5205 case ICmpInst::ICMP_NE:
5206 case ICmpInst::ICMP_UGT:
5207 case ICmpInst::ICMP_SGT:
5208 case ICmpInst::ICMP_SLT:
5209 NewPred = ICmpInst::ICMP_NE;
5219 if (!IsNonNegative &&
5220 (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLE))
5222 if (!IsNonPositive &&
5223 (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGE))
5225 if ((Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLE ||
5226 Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGE) &&
5227 Log2_32(NumElts) >= NumSignBits - 1)
5231 Instruction::Add, VecTy, std::nullopt,
CostKind);
5233 Instruction::Or, VecTy, std::nullopt,
CostKind);
5235 Intrinsic::umax, VecTy, FastMathFlags(),
CostKind);
5238 bool UseOr = OrCost.
isValid() && (!UmaxCost.
isValid() || OrCost <= UmaxCost);
5240 if (AltCost > OrigCost)
5246 Intrinsic::vector_reduce_umax, {VecTy}, {Vec});
5247 Worklist.pushValue(NewReduce);
5249 NewPred, NewReduce, ConstantInt::getNullValue(VecTy->getScalarType()));
5250 replaceValue(
I, *NewCmp);
5259 constexpr unsigned MaxVisited = 32;
5262 bool FoundReduction =
false;
5265 while (!WorkList.
empty()) {
5267 for (
User *U :
I->users()) {
5269 if (!UI || !Visited.
insert(UI).second)
5271 if (Visited.
size() > MaxVisited)
5277 switch (
II->getIntrinsicID()) {
5278 case Intrinsic::vector_reduce_add:
5279 case Intrinsic::vector_reduce_mul:
5280 case Intrinsic::vector_reduce_and:
5281 case Intrinsic::vector_reduce_or:
5282 case Intrinsic::vector_reduce_xor:
5283 case Intrinsic::vector_reduce_smin:
5284 case Intrinsic::vector_reduce_smax:
5285 case Intrinsic::vector_reduce_umin:
5286 case Intrinsic::vector_reduce_umax:
5287 FoundReduction =
true;
5300 return FoundReduction;
5313bool VectorCombine::foldSelectShuffle(Instruction &
I,
bool FromReduction) {
5318 if (!Op0 || !Op1 || Op0 == Op1 || !Op0->isBinaryOp() || !Op1->isBinaryOp() ||
5326 SmallPtrSet<Instruction *, 4> InputShuffles({SVI0A, SVI0B, SVI1A, SVI1B});
5328 if (!
I ||
I->getOperand(0)->getType() != VT)
5330 return any_of(
I->users(), [&](User *U) {
5331 return U != Op0 && U != Op1 &&
5332 !(isa<ShuffleVectorInst>(U) &&
5333 (InputShuffles.contains(cast<Instruction>(U)) ||
5334 isInstructionTriviallyDead(cast<Instruction>(U))));
5337 if (checkSVNonOpUses(SVI0A) || checkSVNonOpUses(SVI0B) ||
5338 checkSVNonOpUses(SVI1A) || checkSVNonOpUses(SVI1B))
5346 for (
auto *U :
I->users()) {
5348 if (!SV || SV->getType() != VT)
5350 if ((SV->getOperand(0) != Op0 && SV->getOperand(0) != Op1) ||
5351 (SV->getOperand(1) != Op0 && SV->getOperand(1) != Op1))
5358 if (!collectShuffles(Op0) || !collectShuffles(Op1))
5362 if (FromReduction && Shuffles.
size() > 1)
5367 if (!FromReduction) {
5368 for (
size_t Idx = 0,
E = Shuffles.
size(); Idx !=
E; ++Idx) {
5369 for (
auto *U : Shuffles[Idx]->
users()) {
5384 int MaxV1Elt = 0, MaxV2Elt = 0;
5385 unsigned NumElts = VT->getNumElements();
5386 for (ShuffleVectorInst *SVN : Shuffles) {
5387 SmallVector<int>
Mask;
5388 SVN->getShuffleMask(Mask);
5392 Value *SVOp0 = SVN->getOperand(0);
5393 Value *SVOp1 = SVN->getOperand(1);
5398 for (
int &Elem : Mask) {
5404 if (SVOp0 == Op1 && SVOp1 == Op0) {
5408 if (SVOp0 != Op0 || SVOp1 != Op1)
5414 SmallVector<int> ReconstructMask;
5415 for (
unsigned I = 0;
I <
Mask.size();
I++) {
5418 }
else if (Mask[
I] <
static_cast<int>(NumElts)) {
5419 MaxV1Elt = std::max(MaxV1Elt, Mask[
I]);
5420 auto It =
find_if(
V1, [&](
const std::pair<int, int> &
A) {
5421 return Mask[
I] ==
A.first;
5427 V1.emplace_back(Mask[
I],
V1.size());
5430 MaxV2Elt = std::max<int>(MaxV2Elt, Mask[
I] - NumElts);
5431 auto It =
find_if(V2, [&](
const std::pair<int, int> &
A) {
5432 return Mask[
I] -
static_cast<int>(NumElts) ==
A.first;
5446 sort(ReconstructMask);
5447 OrigReconstructMasks.
push_back(std::move(ReconstructMask));
5454 if (
V1.empty() || V2.
empty() ||
5455 (MaxV1Elt ==
static_cast<int>(
V1.size()) - 1 &&
5456 MaxV2Elt ==
static_cast<int>(V2.
size()) - 1))
5468 if (InputShuffles.contains(SSV))
5470 return SV->getMaskValue(M);
5478 std::pair<int, int>
Y) {
5479 int MXA = GetBaseMaskValue(
A,
X.first);
5480 int MYA = GetBaseMaskValue(
A,
Y.first);
5484 return SortBase(SVI0A,
A,
B);
5486 stable_sort(V2, [&](std::pair<int, int>
A, std::pair<int, int>
B) {
5487 return SortBase(SVI1A,
A,
B);
5492 for (
const auto &Mask : OrigReconstructMasks) {
5493 SmallVector<int> ReconstructMask;
5494 for (
int M : Mask) {
5496 auto It =
find_if(V, [M](
auto A) {
return A.second ==
M; });
5497 assert(It !=
V.end() &&
"Expected all entries in Mask");
5498 return std::distance(
V.begin(), It);
5502 else if (M <
static_cast<int>(NumElts)) {
5505 ReconstructMask.
push_back(NumElts + FindIndex(V2, M));
5508 ReconstructMasks.
push_back(std::move(ReconstructMask));
5513 SmallVector<int> V1A, V1B, V2A, V2B;
5514 for (
unsigned I = 0;
I <
V1.size();
I++) {
5518 for (
unsigned I = 0;
I < V2.
size();
I++) {
5519 V2A.
push_back(GetBaseMaskValue(SVI1A, V2[
I].first));
5520 V2B.
push_back(GetBaseMaskValue(SVI1B, V2[
I].first));
5522 while (V1A.
size() < NumElts) {
5526 while (V2A.
size() < NumElts) {
5538 VT, VT, SV->getShuffleMask(),
CostKind);
5545 unsigned ElementSize = VT->getElementType()->getPrimitiveSizeInBits();
5546 unsigned MaxVectorSize =
5548 unsigned MaxElementsInVector = MaxVectorSize / ElementSize;
5549 if (MaxElementsInVector == 0)
5558 std::set<SmallVector<int, 4>> UniqueShuffles;
5563 unsigned NumFullVectors =
Mask.size() / MaxElementsInVector;
5564 if (NumFullVectors < 2)
5565 return C + ShuffleCost;
5566 SmallVector<int, 4> SubShuffle(MaxElementsInVector);
5567 unsigned NumUniqueGroups = 0;
5568 unsigned NumGroups =
Mask.size() / MaxElementsInVector;
5571 for (
unsigned I = 0;
I < NumFullVectors; ++
I) {
5572 for (
unsigned J = 0; J < MaxElementsInVector; ++J)
5573 SubShuffle[J] = Mask[MaxElementsInVector *
I + J];
5574 if (UniqueShuffles.insert(SubShuffle).second)
5575 NumUniqueGroups += 1;
5577 return C + ShuffleCost * NumUniqueGroups / NumGroups;
5583 SmallVector<int, 16>
Mask;
5584 SV->getShuffleMask(Mask);
5585 return AddShuffleMaskAdjustedCost(
C, Mask);
5588 auto AllShufflesHaveSameOperands =
5589 [](SmallPtrSetImpl<Instruction *> &InputShuffles) {
5590 if (InputShuffles.size() < 2)
5592 ShuffleVectorInst *FirstSV =
5599 std::next(InputShuffles.begin()), InputShuffles.end(),
5600 [&](Instruction *
I) {
5601 ShuffleVectorInst *SV = dyn_cast<ShuffleVectorInst>(I);
5602 return SV && SV->getOperand(0) == In0 && SV->getOperand(1) == In1;
5611 CostBefore += std::accumulate(Shuffles.begin(), Shuffles.end(),
5613 if (AllShufflesHaveSameOperands(InputShuffles)) {
5614 UniqueShuffles.clear();
5615 CostBefore += std::accumulate(InputShuffles.begin(), InputShuffles.end(),
5618 CostBefore += std::accumulate(InputShuffles.begin(), InputShuffles.end(),
5624 FixedVectorType *Op0SmallVT =
5626 FixedVectorType *Op1SmallVT =
5631 UniqueShuffles.clear();
5632 CostAfter += std::accumulate(ReconstructMasks.begin(), ReconstructMasks.end(),
5634 std::set<SmallVector<int>> OutputShuffleMasks({V1A, V1B, V2A, V2B});
5636 std::accumulate(OutputShuffleMasks.begin(), OutputShuffleMasks.end(),
5639 LLVM_DEBUG(
dbgs() <<
"Found a binop select shuffle pattern: " <<
I <<
"\n");
5641 <<
" vs CostAfter: " << CostAfter <<
"\n");
5642 if (CostBefore < CostAfter ||
5653 if (InputShuffles.contains(SSV))
5655 return SV->getOperand(
Op);
5659 GetShuffleOperand(SVI0A, 1), V1A);
5662 GetShuffleOperand(SVI0B, 1), V1B);
5665 GetShuffleOperand(SVI1A, 1), V2A);
5668 GetShuffleOperand(SVI1B, 1), V2B);
5673 I->copyIRFlags(Op0,
true);
5678 I->copyIRFlags(Op1,
true);
5680 for (
int S = 0,
E = ReconstructMasks.size(); S !=
E; S++) {
5683 replaceValue(*Shuffles[S], *NSV,
false);
5686 Worklist.pushValue(NSV0A);
5687 Worklist.pushValue(NSV0B);
5688 Worklist.pushValue(NSV1A);
5689 Worklist.pushValue(NSV1B);
5699bool VectorCombine::shrinkType(Instruction &
I) {
5700 Value *ZExted, *OtherOperand;
5706 Value *ZExtOperand =
I.getOperand(
I.getOperand(0) == OtherOperand ? 1 : 0);
5710 unsigned BW = SmallTy->getElementType()->getPrimitiveSizeInBits();
5712 if (
I.getOpcode() == Instruction::LShr) {
5729 Instruction::ZExt, BigTy, SmallTy,
5730 TargetTransformInfo::CastContextHint::None,
CostKind);
5735 for (User *U : ZExtOperand->
users()) {
5742 ShrinkCost += ZExtCost;
5757 ShrinkCost += ZExtCost;
5764 Instruction::Trunc, SmallTy, BigTy,
5765 TargetTransformInfo::CastContextHint::None,
CostKind);
5770 if (ShrinkCost > CurrentCost)
5774 Value *Op0 = ZExted;
5777 if (
I.getOperand(0) == OtherOperand)
5784 replaceValue(
I, *NewZExtr);
5790bool VectorCombine::foldInsExtVectorToShuffle(Instruction &
I) {
5791 Value *DstVec, *SrcVec;
5792 uint64_t ExtIdx, InsIdx;
5802 if (!DstVecTy || !SrcVecTy ||
5808 if (InsIdx >= NumDstElts || ExtIdx >= NumSrcElts || NumDstElts == 1)
5815 bool NeedExpOrNarrow = NumSrcElts != NumDstElts;
5817 if (NeedDstSrcSwap) {
5819 Mask[InsIdx] = ExtIdx % NumDstElts;
5823 std::iota(
Mask.begin(),
Mask.end(), 0);
5824 Mask[InsIdx] = (ExtIdx % NumDstElts) + NumDstElts;
5837 SmallVector<int> ExtToVecMask;
5838 if (!NeedExpOrNarrow) {
5843 nullptr, {DstVec, SrcVec});
5849 ExtToVecMask[ExtIdx % NumDstElts] = ExtIdx;
5852 DstVecTy, SrcVecTy, ExtToVecMask,
CostKind);
5856 if (!Ext->hasOneUse())
5859 LLVM_DEBUG(
dbgs() <<
"Found a insert/extract shuffle-like pair: " <<
I
5860 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
5863 if (OldCost < NewCost)
5866 if (NeedExpOrNarrow) {
5867 if (!NeedDstSrcSwap)
5880 replaceValue(
I, *Shuf);
5889bool VectorCombine::foldInterleaveIntrinsics(Instruction &
I) {
5890 const APInt *SplatVal0, *SplatVal1;
5900 auto *ExtVTy = VectorType::getExtendedElementVectorType(VTy);
5901 unsigned Width = VTy->getElementType()->getIntegerBitWidth();
5910 LLVM_DEBUG(
dbgs() <<
"VC: The cost to cast from " << *ExtVTy <<
" to "
5911 << *
I.getType() <<
" is too high.\n");
5915 APInt NewSplatVal = SplatVal1->
zext(Width * 2);
5916 NewSplatVal <<= Width;
5917 NewSplatVal |= SplatVal0->
zext(Width * 2);
5919 ExtVTy->getElementCount(), ConstantInt::get(
F.getContext(), NewSplatVal));
5954bool VectorCombine::foldDeinterleaveIntrinsics(Instruction &
I) {
5956 if (
DL->isBigEndian())
5959 using namespace PatternMatch;
5960 Value *DeinterleavedVal;
5971 unsigned HalfElementWidth = ElementWidth / 2;
5975 std::array<ExtractValueInst *, 2> OrigFields{};
5976 for (User *Usr :
I.users()) {
5979 if (!
E ||
E->getNumIndices() != 1)
5981 unsigned Idx = *
E->idx_begin();
5983 if (Idx >= 2 || OrigFields[Idx] || !
E->hasNUses(2))
5985 OrigFields[Idx] =
E;
5989 SmallVector<Instruction *, 2> MergeInsts;
5990 for (
auto *FieldUsr : OrigFields[0]->
users()) {
5998 auto MatchMerge = [&](void) ->
bool {
6001 return match(MergeInsts[0],
6005 match(MergeInsts[1],
6010 if (!MatchMerge()) {
6011 std::swap(MergeInsts[0], MergeInsts[1]);
6026 auto *NewFieldTy = VecTy->getWithNewBitWidth(HalfElementWidth);
6036 if (OldCost <= NewCost || !NewCost.
isValid()) {
6038 dbgs() <<
"VC: New deinterleave2 sequence cost (" << NewCost <<
")"
6039 <<
" is higher than that of the old one (" << OldCost <<
")\n");
6047 Intrinsic::vector_deinterleave2, {NewVecTy}, {NewVecCast});
6048 for (
auto [Idx, MergeInst] :
enumerate(MergeInsts)) {
6050 NewField = Builder.
CreateBitCast(NewField, MergeInst->getType());
6051 replaceValue(*MergeInst, *NewField);
6057bool VectorCombine::foldBitcastOfVPLoad(Instruction &
I) {
6058 const DataLayout &
DL =
I.getDataLayout();
6073 DL.getValueOrABITypeAlignment(
II->getPointerAlignment(), OrigVecTy);
6074 ElementCount OrigVecCnt = OrigVecTy->getElementCount();
6076 ElementCount NewVecCnt = NewVecTy->getElementCount();
6088 II->getMemoryPointerParam(),
false,
6094 {Intrinsic::vp_load, NewVecTy,
II->getMemoryPointerParam(),
false,
6098 <<
" NewCost=" << NewCost <<
"\n");
6099 if (NewCost > OldCost || !NewCost.
isValid())
6106 NewVecTy, Intrinsic::vp_load,
6107 {
II->getMemoryPointerParam(), NewMask, NewEVL});
6110 0, AttrBuilder(
II->getContext()).addAlignmentAttr(OrigAlign));
6111 replaceValue(*Cast, *NewVP);
6119bool VectorCombine::foldBitOrderReverseAndSwap(Instruction &
I) {
6125 Type *Ty =
I.getType();
6127 TypeSize ElementSize =
DL->getTypeStoreSize(Ty);
6130 Type *NewVecTy = VectorType::get(I8Ty, NewVecCnt);
6146 IntrinsicCostAttributes ICANew(Intrinsic::bitreverse, NewVecTy, {NewVecTy});
6149 InstructionCost NewCost = CastToVecCost + NewIntrinsicCost + CastToOrigCost;
6151 if (!InnerII->hasOneUse())
6155 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
6157 if (!NewCost.
isValid() || NewCost >= OldCost)
6166 replaceValue(
I, *CastToOrig);
6171bool VectorCombine::shrinkLoadForShuffles(Instruction &
I) {
6173 if (!OldLoad || !OldLoad->isSimple())
6180 unsigned const OldNumElements = OldLoadTy->getNumElements();
6186 using IndexRange = std::pair<int, int>;
6187 auto GetIndexRangeInShuffles = [&]() -> std::optional<IndexRange> {
6188 IndexRange OutputRange = IndexRange(OldNumElements, -1);
6189 for (llvm::Use &Use :
I.uses()) {
6191 User *Shuffle =
Use.getUser();
6196 return std::nullopt;
6203 for (
int Index : Mask) {
6204 if (Index >= 0 && Index <
static_cast<int>(OldNumElements)) {
6205 OutputRange.first = std::min(Index, OutputRange.first);
6206 OutputRange.second = std::max(Index, OutputRange.second);
6211 if (OutputRange.second < OutputRange.first)
6212 return std::nullopt;
6218 if (std::optional<IndexRange> Indices = GetIndexRangeInShuffles()) {
6219 unsigned const NewNumElements = Indices->second + 1u;
6223 if (NewNumElements < OldNumElements) {
6228 Type *ElemTy = OldLoadTy->getElementType();
6230 Value *PtrOp = OldLoad->getPointerOperand();
6233 Instruction::Load, OldLoad->getType(), OldLoad->getAlign(),
6234 OldLoad->getPointerAddressSpace(),
CostKind);
6237 OldLoad->getPointerAddressSpace(),
CostKind);
6239 using UseEntry = std::pair<ShuffleVectorInst *, std::vector<int>>;
6241 unsigned const MaxIndex = NewNumElements * 2u;
6243 for (llvm::Use &Use :
I.uses()) {
6250 ArrayRef<int> OldMask = Shuffle->getShuffleMask();
6256 for (
int Index : OldMask) {
6257 if (Index >=
static_cast<int>(MaxIndex))
6271 dbgs() <<
"Found a load used only by shufflevector instructions: "
6272 <<
I <<
"\n OldCost: " << OldCost
6273 <<
" vs NewCost: " << NewCost <<
"\n");
6275 if (OldCost < NewCost || !NewCost.
isValid())
6281 NewLoad->copyMetadata(
I);
6284 for (UseEntry &Use : NewUses) {
6285 ShuffleVectorInst *Shuffle =
Use.first;
6286 std::vector<int> &NewMask =
Use.second;
6293 replaceValue(*Shuffle, *NewShuffle,
false);
6306bool VectorCombine::shrinkPhiOfShuffles(Instruction &
I) {
6308 if (!Phi ||
Phi->getNumIncomingValues() != 2u)
6312 ArrayRef<int> Mask0;
6313 ArrayRef<int> Mask1;
6326 auto const InputNumElements = InputVT->getNumElements();
6328 if (InputNumElements >= ResultVT->getNumElements())
6333 SmallVector<int, 16> NewMask;
6336 for (
auto [
M0,
M1] :
zip(Mask0, Mask1)) {
6337 if (
M0 >= 0 &&
M1 >= 0)
6339 else if (
M0 == -1 &&
M1 == -1)
6352 int MaskOffset = NewMask[0
u];
6353 unsigned Index = (InputNumElements + MaskOffset) % InputNumElements;
6356 for (
unsigned I = 0u;
I < InputNumElements; ++
I) {
6370 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
6373 if (NewCost > OldCost)
6385 auto *NewPhi = Builder.
CreatePHI(NewShuf0->getType(), 2u);
6387 NewPhi->addIncoming(
Op,
Phi->getIncomingBlock(1u));
6393 replaceValue(*Phi, *NewShuf1);
6399bool VectorCombine::run() {
6413 auto Opcode =
I.getOpcode();
6421 if (IsFixedVectorType) {
6423 case Instruction::InsertElement:
6424 if (vectorizeLoadInsert(
I))
6427 case Instruction::ShuffleVector:
6428 if (widenSubvectorLoad(
I))
6439 if (scalarizeOpOrCmp(
I))
6441 if (scalarizeLoad(
I))
6443 if (scalarizeExtExtract(
I))
6445 if (scalarizeVPIntrinsic(
I))
6447 if (foldInterleaveIntrinsics(
I))
6449 if (foldBitcastOfVPLoad(
I))
6453 if (foldDeinterleaveIntrinsics(
I))
6456 if (Opcode == Instruction::Store)
6457 if (foldSingleElementStore(
I))
6461 if (TryEarlyFoldsOnly)
6464 if (Opcode == Instruction::Call)
6465 if (foldBitOrderReverseAndSwap(
I))
6472 if (IsFixedVectorType) {
6474 case Instruction::InsertElement:
6475 if (foldInsExtFNeg(
I))
6477 if (foldInsExtBinop(
I))
6479 if (foldInsExtVectorToShuffle(
I))
6482 case Instruction::ShuffleVector:
6483 if (foldPermuteOfBinops(
I))
6485 if (foldShuffleOfBinops(
I))
6487 if (foldShuffleOfSelects(
I))
6489 if (foldShuffleOfCastops(
I))
6491 if (foldShuffleOfShuffles(
I))
6493 if (foldPermuteOfIntrinsic(
I))
6495 if (foldShufflesOfLengthChangingShuffles(
I))
6497 if (foldShuffleOfIntrinsics(
I))
6499 if (foldSelectShuffle(
I))
6501 if (foldShuffleToIdentity(
I))
6504 case Instruction::Load:
6505 if (shrinkLoadForShuffles(
I))
6508 case Instruction::BitCast:
6509 if (foldBitcastShuffle(
I))
6511 if (foldSelectsFromBitcast(
I))
6514 case Instruction::And:
6515 case Instruction::Or:
6516 case Instruction::Xor:
6517 if (foldBitOpOfCastops(
I))
6519 if (foldBitOpOfCastConstant(
I))
6522 case Instruction::PHI:
6523 if (shrinkPhiOfShuffles(
I))
6533 case Instruction::Call:
6534 if (foldShuffleFromReductions(
I))
6536 if (foldCastFromReductions(
I))
6539 case Instruction::ExtractElement:
6540 if (foldShuffleChainsToReduce(
I))
6543 case Instruction::ICmp:
6544 if (foldSignBitReductionCmp(
I))
6546 if (foldICmpEqZeroVectorReduce(
I))
6548 if (foldReductionZeroTest(
I))
6550 if (foldEquivalentReductionCmp(
I))
6552 if (foldReduceAddCmpZero(
I))
6555 case Instruction::FCmp:
6556 if (foldExtractExtract(
I))
6559 case Instruction::Or:
6560 if (foldConcatOfBoolMasks(
I))
6565 if (foldExtractExtract(
I))
6567 if (foldExtractedCmps(
I))
6569 if (foldBinopOfReductions(
I))
6578 bool MadeChange =
false;
6579 for (BasicBlock &BB :
F) {
6591 if (!
I->isDebugOrPseudoInst())
6592 MadeChange |= FoldInst(*
I);
6599 while (!Worklist.isEmpty()) {
6609 MadeChange |= FoldInst(*
I);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static cl::opt< unsigned > MaxInstrsToScan("aggressive-instcombine-max-scan-instrs", cl::init(64), cl::Hidden, cl::desc("Max number of instructions to scan for aggressive instcombine."))
This is the interface for LLVM's primary stateless and local alias analysis.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static cl::opt< OutputCostKind > CostKind("cost-kind", cl::desc("Target cost kind"), cl::init(OutputCostKind::RecipThroughput), cl::values(clEnumValN(OutputCostKind::RecipThroughput, "throughput", "Reciprocal throughput"), clEnumValN(OutputCostKind::Latency, "latency", "Instruction latency"), clEnumValN(OutputCostKind::CodeSize, "code-size", "Code size"), clEnumValN(OutputCostKind::SizeAndLatency, "size-latency", "Code size and latency"), clEnumValN(OutputCostKind::All, "all", "Print all cost kinds")))
static cl::opt< IntrinsicCostStrategy > IntrinsicCost("intrinsic-cost-strategy", cl::desc("Costing strategy for intrinsic instructions"), cl::init(IntrinsicCostStrategy::InstructionCost), cl::values(clEnumValN(IntrinsicCostStrategy::InstructionCost, "instruction-cost", "Use TargetTransformInfo::getInstructionCost"), clEnumValN(IntrinsicCostStrategy::IntrinsicCost, "intrinsic-cost", "Use TargetTransformInfo::getIntrinsicInstrCost"), clEnumValN(IntrinsicCostStrategy::TypeBasedIntrinsicCost, "type-based-intrinsic-cost", "Calculate the intrinsic cost based only on argument types")))
This file defines the DenseMap class.
This is the interface for a simple mod/ref and alias analysis over globals.
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
static void eraseInstruction(Instruction &I, ICFLoopSafetyInfo &SafetyInfo, MemorySSAUpdater &MSSAU)
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
const SmallVectorImpl< MachineOperand > & Cond
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static SymbolRef::Type getType(const Symbol *Sym)
static bool isFreeConcat(ArrayRef< InstLane > Item, TTI::TargetCostKind CostKind, const TargetTransformInfo &TTI)
Detect concat of multiple values into a vector.
static void analyzeCostOfVecReduction(const IntrinsicInst &II, TTI::TargetCostKind CostKind, const TargetTransformInfo &TTI, InstructionCost &CostBeforeReduction, InstructionCost &CostAfterReduction)
static SmallVector< InstLane > generateInstLaneVectorFromOperand(ArrayRef< InstLane > Item, int Op)
static Value * createShiftShuffle(Value *Vec, unsigned OldIndex, unsigned NewIndex, IRBuilderBase &Builder)
Create a shuffle that translates (shifts) 1 element from the input vector to a new element location.
std::pair< Value *, int > InstLane
static bool isKnownNonPositive(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Used by foldReduceAddCmpZero to check if we can prove that a value is non-positive.
static Align computeAlignmentAfterScalarization(Align VectorAlignment, Type *ScalarType, Value *Idx, const DataLayout &DL)
The memory operation on a vector of ScalarType had alignment of VectorAlignment.
static bool feedsIntoVectorReduction(ShuffleVectorInst *SVI)
Returns true if this ShuffleVectorInst eventually feeds into a vector reduction intrinsic (e....
static cl::opt< bool > DisableVectorCombine("disable-vector-combine", cl::init(false), cl::Hidden, cl::desc("Disable all vector combine transforms"))
static Value * generateNewInstTree(ArrayRef< InstLane > Item, Use *From, const DenseSet< std::pair< Value *, Use * > > &IdentityLeafs, const DenseSet< std::pair< Value *, Use * > > &SplatLeafs, const DenseSet< std::pair< Value *, Use * > > &ConcatLeafs, IRBuilderBase &Builder, const TargetTransformInfo *TTI)
static bool canWidenLoad(LoadInst *Load, const TargetTransformInfo &TTI)
static const unsigned InvalidIndex
static Value * translateExtract(ExtractElementInst *ExtElt, unsigned NewIndex, IRBuilderBase &Builder)
Given an extract element instruction with constant index operand, shuffle the source vector (shift th...
static ScalarizationResult canScalarizeAccess(VectorType *VecTy, Value *Idx, const SimplifyQuery &SQ)
Check if it is legal to scalarize a memory access to VecTy at index Idx.
static cl::opt< unsigned > MaxInstrsToScan("vector-combine-max-scan-instrs", cl::init(30), cl::Hidden, cl::desc("Max number of instructions to scan for vector combining."))
static cl::opt< bool > DisableBinopExtractShuffle("disable-binop-extract-shuffle", cl::init(false), cl::Hidden, cl::desc("Disable binop extract to shuffle transforms"))
static InstLane lookThroughShuffles(Value *V, int Lane)
static bool isMemModifiedBetween(BasicBlock::iterator Begin, BasicBlock::iterator End, const MemoryLocation &Loc, AAResults &AA)
static constexpr int Concat[]
A manager for alias analyses.
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool isNegative() const
Determine sign of this APInt.
unsigned countl_one() const
Count the number of leading one bits.
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
bool isOne() const
Determine if this is a value of 1.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & front() const
Get the first element.
size_t size() const
Get the array size.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
LLVM_ABI bool hasAttribute(Attribute::AttrKind Kind) const
Return true if the attribute exists in this set.
InstListType::iterator iterator
Instruction iterators...
BinaryOps getOpcode() const
Represents analyses that only rely on functions' control flow.
Value * getArgOperand(unsigned i) const
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
void addParamAttrs(unsigned ArgNo, const AttrBuilder &B)
Adds attributes to the indicated argument.
static LLVM_ABI CastInst * Create(Instruction::CastOps, Value *S, Type *Ty, const Twine &Name="", InsertPosition InsertBefore=nullptr)
Provides a way to construct any of the CastInst subclasses using an opcode instead of the subclass's ...
static Type * makeCmpResultType(Type *opnd_type)
Create a result type for fcmp/icmp.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
bool isFPPredicate() const
static LLVM_ABI std::optional< CmpPredicate > getMatching(CmpPredicate A, CmpPredicate B)
Compares two CmpPredicates taking samesign into account and returns the canonicalized CmpPredicate if...
static LLVM_ABI Constant * getExtractElement(Constant *Vec, Constant *Idx, Type *OnlyIfReducedTy=nullptr)
static LLVM_ABI Constant * getBinOpIdentity(unsigned Opcode, Type *Ty, bool AllowRHSConstant=false, bool NSZ=false)
Return the identity constant for a binary opcode.
This is the shared class of boolean and integer constants.
const APInt & getValue() const
Return the constant as an APInt value reference.
This class represents a range of values.
LLVM_ABI ConstantRange urem(const ConstantRange &Other) const
Return a new range representing the possible values resulting from an unsigned remainder operation of...
LLVM_ABI ConstantRange binaryAnd(const ConstantRange &Other) const
Return a new range representing the possible values resulting from a binary-and of a value in this ra...
LLVM_ABI bool contains(const APInt &Val) const
Return true if the specified value is in the set.
static LLVM_ABI Constant * getSplat(ElementCount EC, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
iterator find(const_arg_type_t< KeyT > Val)
Implements a dense probed hash-table based set.
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
static constexpr ElementCount get(ScalarTy MinVal, bool Scalable)
Convenience struct for specifying and reasoning about fast-math flags.
bool noSignedZeros() const
unsigned getNumElements() const
static FixedVectorType * getDoubleElementsVectorType(FixedVectorType *VTy)
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Predicate getSignedPredicate() const
For example, EQ->EQ, SLE->SLE, UGT->SGT, etc.
bool isEquality() const
Return true if this predicate is either EQ or NE.
Common base class shared among various IRBuilders.
LLVM_ABI CallInst * CreateIntrinsicWithoutFolding(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={})
Create a call to intrinsic ID with Args, mangled using OverloadTypes.
Value * CreateNUWMul(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
LoadInst * CreateAlignedLoad(Type *Ty, Value *Ptr, MaybeAlign Align, const char *Name)
LLVM_ABI Value * CreateSelectFMF(Value *C, Value *True, Value *False, FMFSource FMFSource, const Twine &Name="", Instruction *MDFrom=nullptr)
LLVM_ABI Value * CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name="")
Return a vector value that contains.
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
ConstantInt * getTrue()
Get the constant value for i1 true.
LLVM_ABI Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
Value * CreateFreeze(Value *V, const Twine &Name="")
void SetCurrentDebugLocation(const DebugLoc &L)
Set location information used by debugging information.
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Value * CreateCast(Instruction::CastOps Op, Value *V, Type *DestTy, const Twine &Name="", MDNode *FPMathTag=nullptr, FMFSource FMFSource={})
Value * CreateIsNotNeg(Value *Arg, const Twine &Name="")
Return a boolean value testing if Arg > -1.
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
Value * CreatePointerBitCastOrAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name="")
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
LLVM_ABI Value * CreateOrReduce(Value *Src)
Create a vector int OR reduction intrinsic of the source vector.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Value * CreateCmp(CmpInst::Predicate Pred, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
InstTy * Insert(InstTy *I, const Twine &Name="") const
Insert and return the specified instruction.
Value * CreateIsNeg(Value *Arg, const Twine &Name="")
Return a boolean value testing if Arg < 0.
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
LLVM_ABI Value * CreateNAryOp(unsigned Opc, ArrayRef< Value * > Ops, const Twine &Name="", MDNode *FPMathTag=nullptr)
Create either a UnaryOperator or BinaryOperator depending on Opc.
Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)
Value * CreateShuffleVector(Value *V1, Value *V2, Value *Mask, const Twine &Name="")
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
LLVM_ABI Value * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={}, function_ref< void(CallInst *)> SetFn=[](CallInst *) {})
Variant to create a possibly constant-folded intrinsic.
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreateTrunc(Value *V, Type *DestTy, const Twine &Name="", bool IsNUW=false, bool IsNSW=false)
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
Value * CreateBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Value * CreateFNegFMF(Value *V, FMFSource FMFSource, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateICmp(CmpInst::Predicate P, Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
LLVM_ABI Value * CreateUnaryIntrinsic(Intrinsic::ID ID, Value *Op, FMFSource FMFSource={}, const Twine &Name="")
Create a call to intrinsic ID with 1 operand which is mangled on its type.
InstSimplifyFolder - Use InstructionSimplify to fold operations to existing values.
CostType getValue() const
This function is intended to be used as sparingly as possible, since the class provides the full rang...
void push(Instruction *I)
Push the instruction onto the worklist stack.
LLVM_ABI void setHasNoUnsignedWrap(bool b=true)
Set or clear the nuw flag on this instruction, which must be an operator which supports this flag.
LLVM_ABI void copyIRFlags(const Value *V, bool IncludeWrapFlags=true)
Convenience method to copy supported exact, fast-math, and (optionally) wrapping flags from V to this...
LLVM_ABI void setHasNoSignedWrap(bool b=true)
Set or clear the nsw flag on this instruction, which must be an operator which supports this flag.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI void andIRFlags(const Value *V)
Logical 'and' of any supported wrapping, exact, and fast-math flags of V and this instruction.
LLVM_ABI void setNonNeg(bool b=true)
Set or clear the nneg flag on this instruction, which must be a zext instruction.
LLVM_ABI bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
LLVM_ABI FastMathFlags getFastMathFlags() const LLVM_READONLY
Convenience function for getting all the fast-math flags, which must be an operator which supports th...
LLVM_ABI AAMDNodes getAAMetadata() const
Returns the AA metadata for this instruction.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
bool isIdempotent() const
Return true if the instruction is idempotent:
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
LLVM_ABI bool hasAllowReassoc() const LLVM_READONLY
Determine whether the allow-reassociation flag is set.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
A wrapper class for inspecting calls to intrinsic functions.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
An instruction for reading from memory.
unsigned getPointerAddressSpace() const
Returns the address space of the pointer operand.
void setAlignment(Align Align)
Type * getPointerOperandType() const
Align getAlign() const
Return the alignment of the access that is being performed.
Representation for a specific memory location.
static LLVM_ABI MemoryLocation get(const LoadInst *LI)
Return a location with information about the memory reference by the given instruction.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
const SDValue & getOperand(unsigned Num) const
bool contains(const_arg_type key) const
Check if the SetVector contains the given key.
bool empty() const
Determine if the SetVector is empty or not.
bool insert(const value_type &X)
Insert a new element into the SetVector.
This instruction constructs a fixed permutation of two input vectors.
int getMaskValue(unsigned Elt) const
Return the shuffle mask value of this instruction for the given element index.
VectorType * getType() const
Overload to return most specific vector type.
static LLVM_ABI void getShuffleMask(const Constant *Mask, SmallVectorImpl< int > &Result)
Convert the input shuffle mask operand to a vector of integers.
static LLVM_ABI bool isIdentityMask(ArrayRef< int > Mask, int NumSrcElts)
Return true if this shuffle mask chooses elements from exactly one source vector without lane crossin...
static void commuteShuffleMask(MutableArrayRef< int > Mask, unsigned InVecNumElts)
Change values in a shuffle permute mask assuming the two vector operands of length InVecNumElts have ...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
void setAlignment(Align Align)
Analysis pass providing the TargetTransformInfo.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
bool isFPOrFPVectorTy() const
Return true if this is a FP type or a vector of FP.
A Use represents the edge between a Value definition and its users.
Value * getOperand(unsigned i) const
static LLVM_ABI bool isVPBinOp(Intrinsic::ID ID)
std::optional< unsigned > getFunctionalIntrinsicID() const
std::optional< unsigned > getFunctionalOpcode() const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
const Value * stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, APInt &Offset) const
This is a wrapper around stripAndAccumulateConstantOffsets with the in-bounds requirement set to fals...
LLVM_ABI bool hasOneUser() const
Return true if there is exactly one user of this value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
unsigned getValueID() const
Return an ID for the concrete type of this object.
LLVM_ABI bool hasNUses(unsigned N) const
Return true if this Value has exactly N uses.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &)
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
Type * getElementType() const
std::pair< iterator, bool > insert(const ValueT &V)
constexpr bool hasKnownScalarFactor(const FixedOrScalableQuantity &RHS) const
Returns true if there exists a value X where RHS.multiplyCoefficientBy(X) will result in a value whos...
constexpr ScalarTy getFixedValue() const
constexpr ScalarTy getKnownScalarFactor(const FixedOrScalableQuantity &RHS) const
Returns a value X where RHS.multiplyCoefficientBy(X) will result in a value whose quantity matches ou...
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
const APInt & smin(const APInt &A, const APInt &B)
Determine the smaller of two APInts considered to be signed.
const APInt & smax(const APInt &A, const APInt &B)
Determine the larger of two APInts considered to be signed.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
LLVM_ABI AttributeSet getFnAttributes(LLVMContext &C, ID id)
Return the function attributes for an intrinsic.
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
match_combine_and< Ty... > m_CombineAnd(const Ty &...Ps)
Combine pattern matchers matching all of Ps patterns.
cst_pred_ty< is_all_ones > m_AllOnes()
Match an integer or vector with all bits set.
BinaryOp_match< LHS, RHS, Instruction::And > m_And(const LHS &L, const RHS &R)
auto m_BSwap(const Opnd0 &Op0)
auto m_Cmp()
Matches any compare instruction and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Add > m_Add(const LHS &L, const RHS &R)
auto m_BitReverse(const Opnd0 &Op0)
BinaryOp_match< LHS, RHS, Instruction::URem > m_URem(const LHS &L, const RHS &R)
auto m_Poison()
Match an arbitrary poison constant.
ap_match< APInt > m_APInt(const APInt *&Res)
Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.
CastInst_match< OpTy, TruncInst > m_Trunc(const OpTy &Op)
Matches Trunc.
specific_intval< false > m_SpecificInt(const APInt &V)
Match a specific integer value or vector with all elements equal to the value.
bool match(Val *V, const Pattern &P)
match_bind< Instruction > m_Instruction(Instruction *&I)
Match an instruction, capturing it if we match.
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
DisjointOr_match< LHS, RHS > m_DisjointOr(const LHS &L, const RHS &R)
BinOpPred_match< LHS, RHS, is_right_shift_op > m_Shr(const LHS &L, const RHS &R)
Matches logical shift operations.
CmpClass_match< LHS, RHS, ICmpInst, true > m_c_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
Matches an ICmp with a predicate over LHS and RHS in either order.
TwoOps_match< Val_t, Idx_t, Instruction::ExtractElement > m_ExtractElt(const Val_t &Val, const Idx_t &Idx)
Matches ExtractElementInst.
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
auto m_BinOp()
Match an arbitrary binary operation and ignore it.
auto m_Value()
Match an arbitrary value and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
auto m_Constant()
Match an arbitrary Constant and ignore it.
TwoOps_match< V1_t, V2_t, Instruction::ShuffleVector > m_Shuffle(const V1_t &v1, const V2_t &v2)
Matches ShuffleVectorInst independently of mask value.
cst_pred_ty< is_non_zero_int > m_NonZeroInt()
Match a non-zero integer or a vector with all non-zero elements.
OneOps_match< OpTy, Instruction::Load > m_Load(const OpTy &Op)
Matches LoadInst.
CastInst_match< OpTy, ZExtInst > m_ZExt(const OpTy &Op)
Matches ZExt.
OverflowingBinaryOp_match< LHS, RHS, Instruction::Shl, OverflowingBinaryOperator::NoUnsignedWrap > m_NUWShl(const LHS &L, const RHS &R)
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
OverflowingBinaryOp_match< LHS, RHS, Instruction::Mul, OverflowingBinaryOperator::NoUnsignedWrap > m_NUWMul(const LHS &L, const RHS &R)
BinOpPred_match< LHS, RHS, is_bitwiselogic_op, true > m_c_BitwiseLogic(const LHS &L, const RHS &R)
Matches bitwise logic operations in either order.
CastOperator_match< OpTy, Instruction::BitCast > m_BitCast(const OpTy &Op)
Matches BitCast.
match_combine_or< CastInst_match< OpTy, SExtInst >, NNegZExt_match< OpTy > > m_SExtLike(const OpTy &Op)
Match either "sext" or "zext nneg".
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
auto m_Deinterleave2(const Opnd &Op)
BinaryOp_match< LHS, RHS, Instruction::LShr > m_LShr(const LHS &L, const RHS &R)
CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
match_combine_or< CastInst_match< OpTy, ZExtInst >, CastInst_match< OpTy, SExtInst > > m_ZExtOrSExt(const OpTy &Op)
FNeg_match< OpTy > m_FNeg(const OpTy &X)
Match 'fneg X' as 'fsub -0.0, X'.
BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)
auto m_Undef()
Match an arbitrary undef constant.
CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)
Matches SExt.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
BinaryOp_match< LHS, RHS, Instruction::Or, true > m_c_Or(const LHS &L, const RHS &R)
Matches an Or with LHS and RHS in either order.
ThreeOps_match< Val_t, Elt_t, Idx_t, Instruction::InsertElement > m_InsertElt(const Val_t &Val, const Elt_t &Elt, const Idx_t &Idx)
Matches InsertElementInst.
auto m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
@ Valid
The data is already valid.
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
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.
unsigned Log2_32_Ceil(uint32_t Value)
Return the ceil log base 2 of the specified value, 32 if the value is zero.
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
void stable_sort(R &&Range)
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Intrinsic::ID getMinMaxReductionIntrinsicOp(Intrinsic::ID RdxID)
Returns the min/max intrinsic used when expanding a min/max reduction.
LLVM_ABI bool RecursivelyDeleteTriviallyDeadInstructions(Value *V, const TargetLibraryInfo *TLI=nullptr, MemorySSAUpdater *MSSAU=nullptr, std::function< void(Value *)> AboutToDeleteCallback=std::function< void(Value *)>())
If the specified value is a trivially dead instruction, delete it.
RelativeUniformCounterPtr Values
LLVM_ABI SDValue peekThroughBitcasts(SDValue V)
Return the non-bitcasted source operand of V if it exists.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI Value * simplifyUnOp(unsigned Opcode, Value *Op, const SimplifyQuery &Q)
Given operand for a UnaryOperator, fold the result or return null.
scope_exit(Callable) -> scope_exit< Callable >
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
LLVM_ABI unsigned getArithmeticReductionInstruction(Intrinsic::ID RdxID)
Returns the arithmetic instruction opcode used when expanding a reduction.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
constexpr bool isUIntN(unsigned N, uint64_t x)
Checks if an unsigned integer fits into the given (dynamic) bit width.
LLVM_ABI Value * simplifyCall(CallBase *Call, Value *Callee, ArrayRef< Value * > Args, const SimplifyQuery &Q)
Given a callsite, callee, and arguments, fold the result or return null.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
LLVM_ABI bool mustSuppressSpeculation(const LoadInst &LI)
Return true if speculation of the given load must be suppressed to avoid ordering or interfering with...
LLVM_ABI bool widenShuffleMaskElts(int Scale, ArrayRef< int > Mask, SmallVectorImpl< int > &ScaledMask)
Try to transform a shuffle mask by replacing elements with the scaled index for an equivalent mask of...
LLVM_ABI bool isSafeToSpeculativelyExecute(const Instruction *I, const Instruction *CtxI=nullptr, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr, const TargetLibraryInfo *TLI=nullptr, bool UseVariableInfo=true, bool IgnoreUBImplyingAttrs=true)
Return true if the instruction does not have any effects besides calculating the result and does not ...
LLVM_ABI Value * getSplatValue(const Value *V)
Get splat value if the input is a splat vector or return nullptr.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
unsigned M1(unsigned Val)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI bool isInstructionTriviallyDead(Instruction *I, const TargetLibraryInfo *TLI=nullptr)
Return true if the result produced by the instruction is not used, and the instruction will return.
LLVM_ABI bool isSplatValue(const Value *V, int Index=-1, unsigned Depth=0)
Return true if each element of the vector value V is poisoned or equal to every other non-poisoned el...
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
auto reverse(ContainerTy &&C)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
bool isModSet(const ModRefInfo MRI)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Determine which bits of V are known to be either zero or one and return them in the KnownZero/KnownOn...
LLVM_ABI bool programUndefinedIfPoison(const Instruction *Inst)
LLVM_ABI bool isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &Size, const DataLayout &DL, Instruction *ScanFrom, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr, const TargetLibraryInfo *TLI=nullptr)
Return true if we know that executing a load from this value cannot trap.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI void propagateIRFlags(Value *I, ArrayRef< Value * > VL, Value *OpValue=nullptr, bool IncludeWrapFlags=true)
Get the intersection (logical and) of all of the potential IR flags of each scalar operation (VL) tha...
LLVM_ABI bool isKnownNonZero(const Value *V, const SimplifyQuery &Q, unsigned Depth=0)
Return true if the given value is known to be non-zero when defined.
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
constexpr int PoisonMaskElem
LLVM_ABI bool isSafeToSpeculativelyExecuteWithOpcode(unsigned Opcode, const Instruction *Inst, const Instruction *CtxI=nullptr, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr, const TargetLibraryInfo *TLI=nullptr, bool UseVariableInfo=true, bool IgnoreUBImplyingAttrs=true)
This returns the same result as isSafeToSpeculativelyExecute if Opcode is the actual opcode of Inst.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
LLVM_ABI Value * simplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, const SimplifyQuery &Q)
Given operands for a BinaryOperator, fold the result or return null.
LLVM_ABI void narrowShuffleMaskElts(int Scale, ArrayRef< int > Mask, SmallVectorImpl< int > &ScaledMask)
Replace each shuffle mask index with the scaled sequential indices for an equivalent mask of narrowed...
LLVM_ABI Intrinsic::ID getReductionForBinop(Instruction::BinaryOps Opc)
Returns the reduction intrinsic id corresponding to the binary operation.
@ And
Bitwise or logical AND of integers.
LLVM_ABI bool isVectorIntrinsicWithScalarOpAtArg(Intrinsic::ID ID, unsigned ScalarOpdIdx, const TargetTransformInfo *TTI)
Identifies if the vector form of the intrinsic has a scalar operand.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
DWARFExpression::Operation Op
unsigned M0(unsigned Val)
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI unsigned ComputeNumSignBits(const Value *Op, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Return the number of times the sign bit of the register is replicated into the other bits.
constexpr unsigned BitWidth
LLVM_ABI bool isGuaranteedToTransferExecutionToSuccessor(const Instruction *I)
Return true if this function can prove that the instruction I will always transfer execution to one o...
LLVM_ABI Constant * getLosslessInvCast(Constant *C, Type *InvCastTo, unsigned CastOp, const DataLayout &DL, PreservedCastFlags *Flags=nullptr)
Try to cast C to InvC losslessly, satisfying CastOp(InvC) equals C, or CastOp(InvC) is a refined valu...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
constexpr bool isIntN(unsigned N, int64_t x)
Checks if an signed integer fits into the given (dynamic) bit width.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
bool all_equal(std::initializer_list< T > Values)
Returns true if all Values in the initializer lists are equal or the list.
LLVM_ABI Value * simplifyCmpInst(CmpPredicate Predicate, Value *LHS, Value *RHS, const SimplifyQuery &Q)
Given operands for a CmpInst, fold the result or return null.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI bool isGuaranteedNotToBePoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Returns true if V cannot be poison, but may be undef.
LLVM_ABI bool isKnownNonNegative(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Returns true if the give value is known to be non-negative.
LLVM_ABI bool isTriviallyVectorizable(Intrinsic::ID ID)
Identify if the intrinsic is trivially vectorizable.
LLVM_ABI Intrinsic::ID getMinMaxReductionIntrinsicID(Intrinsic::ID IID)
Returns the llvm.vector.reduce min/max intrinsic that corresponds to the intrinsic op.
LLVM_ABI ConstantRange computeConstantRange(const Value *V, bool ForSigned, const SimplifyQuery &SQ, unsigned Depth=0)
Determine the possible constant range of an integer or vector of integer value.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
LLVM_ABI AAMDNodes adjustForAccess(unsigned AccessSize)
Create a new AAMDNode for accessing AccessSize bytes of this AAMDNode.
This struct is a compact representation of a valid (non-zero power of two) alignment.
unsigned countMaxActiveBits() const
Returns the maximum number of bits needed to represent all possible unsigned values with these known ...
unsigned countMinLeadingZeros() const
Returns the minimum number of leading zero bits.
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.
SimplifyQuery getWithInstruction(const Instruction *I) const