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);
224 return X->getType() ==
Y->getType() &&
233 Load->getFunction()->hasFnAttribute(Attribute::SanitizeMemTag) ||
239 Type *ScalarTy =
Load->getType()->getScalarType();
241 unsigned MinVectorSize =
TTI.getMinVectorRegisterBitWidth();
242 if (!ScalarSize || !MinVectorSize || MinVectorSize % ScalarSize != 0 ||
249bool VectorCombine::vectorizeLoadInsert(
Instruction &
I) {
275 Value *SrcPtr =
Load->getPointerOperand()->stripPointerCasts();
278 unsigned MinVecNumElts = MinVectorSize / ScalarSize;
279 auto *MinVecTy = VectorType::get(ScalarTy, MinVecNumElts,
false);
280 unsigned OffsetEltIndex = 0;
288 unsigned OffsetBitWidth =
DL->getIndexTypeSizeInBits(SrcPtr->
getType());
289 APInt
Offset(OffsetBitWidth, 0);
299 uint64_t ScalarSizeInBytes = ScalarSize / 8;
300 if (
Offset.urem(ScalarSizeInBytes) != 0)
304 APInt OffsetEltIndexAP =
Offset.udiv(ScalarSizeInBytes);
305 if (OffsetEltIndexAP.
uge(MinVecNumElts))
323 unsigned AS =
Load->getPointerAddressSpace();
342 unsigned OutputNumElts = Ty->getNumElements();
344 assert(OffsetEltIndex < MinVecNumElts &&
"Address offset too big");
345 Mask[0] = OffsetEltIndex;
352 if (OldCost < NewCost || !NewCost.
isValid())
363 replaceValue(
I, *VecLd);
371bool VectorCombine::widenSubvectorLoad(Instruction &
I) {
374 if (!Shuf->isIdentityWithPadding())
380 unsigned OpIndex =
any_of(Shuf->getShuffleMask(), [&NumOpElts](
int M) {
381 return M >= (int)(NumOpElts);
401 unsigned AS =
Load->getPointerAddressSpace();
416 if (OldCost < NewCost || !NewCost.
isValid())
423 replaceValue(
I, *VecLd);
430ExtractElementInst *VectorCombine::getShuffleExtract(
431 ExtractElementInst *Ext0, ExtractElementInst *Ext1,
435 assert(Index0C && Index1C &&
"Expected constant extract indexes");
437 unsigned Index0 = Index0C->getZExtValue();
438 unsigned Index1 = Index1C->getZExtValue();
441 if (Index0 == Index1)
465 if (PreferredExtractIndex == Index0)
467 if (PreferredExtractIndex == Index1)
471 return Index0 > Index1 ? Ext0 : Ext1;
479bool VectorCombine::isExtractExtractCheap(ExtractElementInst *Ext0,
480 ExtractElementInst *Ext1,
481 const Instruction &
I,
482 ExtractElementInst *&ConvertToShuffle,
483 unsigned PreferredExtractIndex) {
486 assert(Ext0IndexC && Ext1IndexC &&
"Expected constant extract indexes");
488 unsigned Opcode =
I.getOpcode();
501 assert((Opcode == Instruction::ICmp || Opcode == Instruction::FCmp) &&
502 "Expected a compare");
512 unsigned Ext0Index = Ext0IndexC->getZExtValue();
513 unsigned Ext1Index = Ext1IndexC->getZExtValue();
527 unsigned BestExtIndex = Extract0Cost > Extract1Cost ? Ext0Index : Ext1Index;
528 unsigned BestInsIndex = Extract0Cost > Extract1Cost ? Ext1Index : Ext0Index;
529 InstructionCost CheapExtractCost = std::min(Extract0Cost, Extract1Cost);
534 if (Ext0Src == Ext1Src && Ext0Index == Ext1Index) {
539 bool HasUseTax = Ext0 == Ext1 ? !Ext0->
hasNUses(2)
541 OldCost = CheapExtractCost + ScalarOpCost;
542 NewCost = VectorOpCost + CheapExtractCost + HasUseTax * CheapExtractCost;
546 OldCost = Extract0Cost + Extract1Cost + ScalarOpCost;
547 NewCost = VectorOpCost + CheapExtractCost +
552 ConvertToShuffle = getShuffleExtract(Ext0, Ext1, PreferredExtractIndex);
553 if (ConvertToShuffle) {
565 SmallVector<int> ShuffleMask(FixedVecTy->getNumElements(),
567 ShuffleMask[BestInsIndex] = BestExtIndex;
569 VecTy, VecTy, ShuffleMask,
CostKind, 0,
570 nullptr, {ConvertToShuffle});
573 VecTy, VecTy, {},
CostKind, 0,
nullptr,
578 LLVM_DEBUG(
dbgs() <<
"Found a binop of extractions: " <<
I <<
"\n OldCost: "
579 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
584 return OldCost < NewCost;
596 ShufMask[NewIndex] = OldIndex;
597 return Builder.CreateShuffleVector(Vec, ShufMask,
"shift");
649 V1,
"foldExtExtBinop");
654 VecBOInst->copyIRFlags(&
I);
660bool VectorCombine::foldExtractExtract(Instruction &
I) {
681 unsigned NumElts = FixedVecTy->getNumElements();
682 if (C0 >= NumElts || C1 >= NumElts)
698 ExtractElementInst *ExtractToChange;
699 if (isExtractExtractCheap(Ext0, Ext1,
I, ExtractToChange, InsertIndex))
705 if (ExtractToChange) {
706 unsigned CheapExtractIdx = ExtractToChange == Ext0 ? C1 : C0;
711 if (ExtractToChange == Ext0)
720 ? foldExtExtCmp(ExtOp0, ExtOp1, ExtIndex,
I)
721 : foldExtExtBinop(ExtOp0, ExtOp1, ExtIndex,
I);
724 replaceValue(
I, *NewExt);
730bool VectorCombine::foldInsExtFNeg(Instruction &
I) {
733 uint64_t ExtIdx, InsIdx;
748 auto *DstVecScalarTy = DstVecTy->getScalarType();
750 if (!SrcVecTy || DstVecScalarTy != SrcVecTy->getScalarType())
755 unsigned NumDstElts = DstVecTy->getNumElements();
756 unsigned NumSrcElts = SrcVecTy->getNumElements();
757 if (ExtIdx > NumSrcElts || InsIdx >= NumDstElts || NumDstElts == 1)
763 SmallVector<int>
Mask(NumDstElts);
764 std::iota(
Mask.begin(),
Mask.end(), 0);
765 Mask[InsIdx] = (ExtIdx % NumDstElts) + NumDstElts;
781 bool NeedLenChg = SrcVecTy->getNumElements() != NumDstElts;
784 SmallVector<int> SrcMask;
787 SrcMask[ExtIdx % NumDstElts] = ExtIdx;
789 DstVecTy, SrcVecTy, SrcMask,
CostKind);
793 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
795 if (NewCost > OldCost)
798 Value *NewShuf, *LenChgShuf =
nullptr;
812 replaceValue(
I, *NewShuf);
818bool VectorCombine::foldInsExtBinop(Instruction &
I) {
819 BinaryOperator *VecBinOp, *SclBinOp;
851 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
853 if (NewCost > OldCost)
864 NewInst->copyIRFlags(VecBinOp);
865 NewInst->andIRFlags(SclBinOp);
870 replaceValue(
I, *NewBO);
876bool VectorCombine::foldBitOpOfCastops(Instruction &
I) {
879 if (!BinOp || !BinOp->isBitwiseLogicOp())
885 if (!LHSCast || !RHSCast) {
886 LLVM_DEBUG(
dbgs() <<
" One or both operands are not cast instructions\n");
892 if (CastOpcode != RHSCast->getOpcode())
896 switch (CastOpcode) {
897 case Instruction::BitCast:
898 case Instruction::Trunc:
899 case Instruction::SExt:
900 case Instruction::ZExt:
906 Value *LHSSrc = LHSCast->getOperand(0);
907 Value *RHSSrc = RHSCast->getOperand(0);
913 auto *SrcTy = LHSSrc->
getType();
914 auto *DstTy =
I.getType();
917 if (CastOpcode != Instruction::BitCast &&
922 if (!SrcTy->getScalarType()->isIntegerTy() ||
923 !DstTy->getScalarType()->isIntegerTy())
938 LHSCastCost + RHSCastCost;
949 if (!LHSCast->hasOneUse())
950 NewCost += LHSCastCost;
951 if (!RHSCast->hasOneUse())
952 NewCost += RHSCastCost;
955 <<
" NewCost=" << NewCost <<
"\n");
957 if (NewCost > OldCost)
962 BinOp->getName() +
".inner");
964 NewBinOp->copyIRFlags(BinOp);
978 replaceValue(
I, *Result);
987bool VectorCombine::foldBitOpOfCastConstant(Instruction &
I) {
1003 switch (CastOpcode) {
1004 case Instruction::BitCast:
1005 case Instruction::ZExt:
1006 case Instruction::SExt:
1007 case Instruction::Trunc:
1013 Value *LHSSrc = LHSCast->getOperand(0);
1015 auto *SrcTy = LHSSrc->
getType();
1016 auto *DstTy =
I.getType();
1019 if (CastOpcode != Instruction::BitCast &&
1024 if (!SrcTy->getScalarType()->isIntegerTy() ||
1025 !DstTy->getScalarType()->isIntegerTy())
1029 PreservedCastFlags RHSFlags;
1054 if (!LHSCast->hasOneUse())
1055 NewCost += LHSCastCost;
1057 LLVM_DEBUG(
dbgs() <<
"foldBitOpOfCastConstant: OldCost=" << OldCost
1058 <<
" NewCost=" << NewCost <<
"\n");
1060 if (NewCost > OldCost)
1065 LHSSrc, InvC,
I.getName() +
".inner");
1067 NewBinOp->copyIRFlags(&
I);
1087 replaceValue(
I, *Result);
1094bool VectorCombine::foldBitcastShuffle(Instruction &
I) {
1108 if (!DestTy || !SrcTy)
1111 unsigned DestEltSize = DestTy->getScalarSizeInBits();
1112 unsigned SrcEltSize = SrcTy->getScalarSizeInBits();
1113 if (SrcTy->getPrimitiveSizeInBits() % DestEltSize != 0)
1123 if (!(BCTy0 && BCTy0->getElementType() == DestTy->getElementType()) &&
1124 !(BCTy1 && BCTy1->getElementType() == DestTy->getElementType()))
1128 SmallVector<int, 16> NewMask;
1129 if (DestEltSize <= SrcEltSize) {
1132 if (SrcEltSize % DestEltSize != 0)
1134 unsigned ScaleFactor = SrcEltSize / DestEltSize;
1139 if (DestEltSize % SrcEltSize != 0)
1141 unsigned ScaleFactor = DestEltSize / SrcEltSize;
1148 unsigned NumSrcElts = SrcTy->getPrimitiveSizeInBits() / DestEltSize;
1149 auto *NewShuffleTy =
1151 auto *OldShuffleTy =
1153 unsigned NumOps = IsUnary ? 1 : 2;
1163 TargetTransformInfo::CastContextHint::None,
1168 TargetTransformInfo::CastContextHint::None,
1171 LLVM_DEBUG(
dbgs() <<
"Found a bitcasted shuffle: " <<
I <<
"\n OldCost: "
1172 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
1174 if (NewCost > OldCost || !NewCost.
isValid())
1182 replaceValue(
I, *Shuf);
1189bool VectorCombine::scalarizeVPIntrinsic(Instruction &
I) {
1203 if (!ScalarOp0 || !ScalarOp1)
1211 auto IsAllTrueMask = [](
Value *MaskVal) {
1214 return ConstValue->isAllOnesValue();
1228 SmallVector<int>
Mask;
1230 Mask.resize(FVTy->getNumElements(), 0);
1239 Args.push_back(
V->getType());
1240 IntrinsicCostAttributes
Attrs(IntrID, VecTy, Args);
1245 std::optional<unsigned> FunctionalOpcode =
1247 std::optional<Intrinsic::ID> ScalarIntrID = std::nullopt;
1248 if (!FunctionalOpcode) {
1257 IntrinsicCostAttributes
Attrs(*ScalarIntrID, VecTy->getScalarType(), Args);
1267 InstructionCost NewCost = ScalarOpCost + SplatCost + CostToKeepSplats;
1269 LLVM_DEBUG(
dbgs() <<
"Found a VP Intrinsic to scalarize: " << VPI
1272 <<
", Cost of scalarizing:" << NewCost <<
"\n");
1275 if (OldCost < NewCost || !NewCost.
isValid())
1286 bool SafeToSpeculate;
1292 *FunctionalOpcode, &VPI,
nullptr, SQ.
AC, SQ.
DT);
1293 if (!SafeToSpeculate &&
1300 {ScalarOp0, ScalarOp1})
1302 ScalarOp0, ScalarOp1);
1311bool VectorCombine::scalarizeOpOrCmp(Instruction &
I) {
1316 if (!UO && !BO && !CI && !
II)
1324 if (Arg->getType() !=
II->getType() &&
1334 for (User *U :
I.users())
1341 std::optional<uint64_t>
Index;
1343 auto Ops =
II ?
II->args() :
I.operands();
1347 uint64_t InsIdx = 0;
1352 if (OpTy->getElementCount().getKnownMinValue() <= InsIdx)
1358 else if (InsIdx != *Index)
1375 if (!
Index.has_value())
1379 Type *ScalarTy = VecTy->getScalarType();
1380 assert(VecTy->isVectorTy() &&
1383 "Unexpected types for insert element into binop or cmp");
1385 unsigned Opcode =
I.getOpcode();
1393 }
else if (UO || BO) {
1397 IntrinsicCostAttributes ScalarICA(
1398 II->getIntrinsicID(), ScalarTy,
1401 IntrinsicCostAttributes VectorICA(
1402 II->getIntrinsicID(), VecTy,
1409 Value *NewVecC =
nullptr;
1411 NewVecC =
simplifyCmpInst(CI->getPredicate(), VecCs[0], VecCs[1], SQ);
1414 simplifyUnOp(UO->getOpcode(), VecCs[0], UO->getFastMathFlags(), SQ);
1416 NewVecC =
simplifyBinOp(BO->getOpcode(), VecCs[0], VecCs[1], SQ);
1430 for (
auto [Idx,
Op, VecC, Scalar] :
enumerate(
Ops, VecCs, ScalarOps)) {
1432 II->getIntrinsicID(), Idx, &
TTI)))
1435 Instruction::InsertElement, VecTy,
CostKind, *Index, VecC, Scalar);
1436 OldCost += InsertCost;
1437 NewCost += !
Op->hasOneUse() * InsertCost;
1441 if (OldCost < NewCost || !NewCost.
isValid())
1451 ++NumScalarIntrinsic;
1454 for (
auto [OpIdx, Scalar, VecC] :
enumerate(ScalarOps, VecCs))
1461 Scalar = Builder.
CreateCmp(CI->getPredicate(), ScalarOps[0], ScalarOps[1]);
1467 Scalar->setName(
I.getName() +
".scalar");
1472 ScalarInst->copyIRFlags(&
I);
1475 replaceValue(
I, *Insert);
1482bool VectorCombine::foldExtractedCmps(Instruction &
I) {
1487 if (!BI || !
I.getType()->isIntegerTy(1))
1492 Value *B0 =
I.getOperand(0), *
B1 =
I.getOperand(1);
1495 CmpPredicate
P0,
P1;
1507 uint64_t Index0, Index1;
1514 ExtractElementInst *ConvertToShuf = getShuffleExtract(Ext0, Ext1,
CostKind);
1517 assert((ConvertToShuf == Ext0 || ConvertToShuf == Ext1) &&
1518 "Unknown ExtractElementInst");
1523 unsigned CmpOpcode =
1529 if (Index0 >= VecTy->getNumElements() || Index1 >= VecTy->getNumElements())
1541 Ext0Cost + Ext1Cost + CmpCost * 2 +
1547 int CheapIndex = ConvertToShuf == Ext0 ? Index1 : Index0;
1548 int ExpensiveIndex = ConvertToShuf == Ext0 ? Index0 : Index1;
1553 ShufMask[CheapIndex] = ExpensiveIndex;
1558 NewCost += Ext0->
hasOneUse() ? 0 : Ext0Cost;
1559 NewCost += Ext1->
hasOneUse() ? 0 : Ext1Cost;
1564 if (OldCost < NewCost || !NewCost.
isValid())
1574 Value *
LHS = ConvertToShuf == Ext0 ? Shuf : VCmp;
1575 Value *
RHS = ConvertToShuf == Ext0 ? VCmp : Shuf;
1578 replaceValue(
I, *NewExt);
1605bool VectorCombine::foldSelectsFromBitcast(Instruction &
I) {
1612 if (!SrcVecTy || !DstVecTy)
1622 if (SrcEltBits != 32 && SrcEltBits != 64)
1625 if (!DstEltTy->
isIntegerTy() || DstEltBits >= SrcEltBits)
1642 if (!ScalarSelCost.
isValid() || ScalarSelCost == 0)
1645 unsigned MinSelects = (VecSelCost.
getValue() / ScalarSelCost.
getValue()) + 1;
1648 if (!BC->hasNUsesOrMore(MinSelects))
1653 DenseMap<Value *, SmallVector<SelectInst *, 8>> CondToSelects;
1655 for (User *U : BC->users()) {
1660 for (User *ExtUser : Ext->users()) {
1664 Cond->getType()->isIntegerTy(1))
1669 if (CondToSelects.
empty())
1672 bool MadeChange =
false;
1673 Value *SrcVec = BC->getOperand(0);
1676 for (
auto [
Cond, Selects] : CondToSelects) {
1678 if (Selects.size() < MinSelects) {
1679 LLVM_DEBUG(
dbgs() <<
"VectorCombine: foldSelectsFromBitcast not "
1680 <<
"profitable (VecCost=" << VecSelCost
1681 <<
", ScalarCost=" << ScalarSelCost
1682 <<
", NumSelects=" << Selects.size() <<
")\n");
1687 auto InsertPt = std::next(BC->getIterator());
1691 InsertPt = std::next(CondInst->getIterator());
1699 for (SelectInst *Sel : Selects) {
1701 Value *Idx = Ext->getIndexOperand();
1705 replaceValue(*Sel, *NewExt);
1710 <<
" selects into vector select\n");
1724 unsigned ReductionOpc =
1730 CostBeforeReduction =
1731 TTI.getCastInstrCost(RedOp->getOpcode(), VecRedTy, ExtType,
1733 CostAfterReduction =
1734 TTI.getExtendedReductionCost(ReductionOpc, IsUnsigned,
II.getType(),
1738 if (RedOp &&
II.getIntrinsicID() == Intrinsic::vector_reduce_add &&
1744 (Op0->
getOpcode() == RedOp->getOpcode() || Op0 == Op1)) {
1751 TTI.getCastInstrCost(Op0->
getOpcode(), MulType, ExtType,
1754 TTI.getArithmeticInstrCost(Instruction::Mul, MulType,
CostKind);
1756 TTI.getCastInstrCost(RedOp->getOpcode(), VecRedTy, MulType,
1759 CostBeforeReduction = ExtCost * 2 + MulCost + Ext2Cost;
1760 CostAfterReduction =
TTI.getMulAccReductionCost(
1761 IsUnsigned, ReductionOpc,
II.getType(), ExtType,
CostKind);
1764 CostAfterReduction =
TTI.getArithmeticReductionCost(ReductionOpc, VecRedTy,
1768bool VectorCombine::foldBinopOfReductions(Instruction &
I) {
1771 if (BinOpOpc == Instruction::Sub)
1772 ReductionIID = Intrinsic::vector_reduce_add;
1776 if (ReductionIID == Intrinsic::vector_reduce_fadd ||
1777 ReductionIID == Intrinsic::vector_reduce_fmul)
1780 auto checkIntrinsicAndGetItsArgument = [](
Value *
V,
1785 if (
II->getIntrinsicID() == IID &&
II->hasOneUse())
1786 return II->getArgOperand(0);
1790 Value *V0 = checkIntrinsicAndGetItsArgument(
I.getOperand(0), ReductionIID);
1793 Value *
V1 = checkIntrinsicAndGetItsArgument(
I.getOperand(1), ReductionIID);
1798 if (
V1->getType() != VTy)
1802 unsigned ReductionOpc =
1815 CostOfRedOperand0 + CostOfRedOperand1 +
1818 if (NewCost >= OldCost || !NewCost.
isValid())
1822 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
1825 if (BinOpOpc == Instruction::Or)
1832 replaceValue(
I, *Rdx);
1840 unsigned NumScanned = 0;
1841 return std::any_of(Begin, End, [&](
const Instruction &Instr) {
1850class ScalarizationResult {
1851 enum class StatusTy { Unsafe, Safe, SafeWithFreeze };
1856 ScalarizationResult(StatusTy Status,
Value *ToFreeze =
nullptr)
1857 : Status(Status), ToFreeze(ToFreeze) {}
1860 ScalarizationResult(
const ScalarizationResult &
Other) =
default;
1861 ~ScalarizationResult() {
1862 assert(!ToFreeze &&
"freeze() not called with ToFreeze being set");
1865 static ScalarizationResult unsafe() {
return {StatusTy::Unsafe}; }
1866 static ScalarizationResult safe() {
return {StatusTy::Safe}; }
1867 static ScalarizationResult safeWithFreeze(
Value *ToFreeze) {
1868 return {StatusTy::SafeWithFreeze, ToFreeze};
1872 bool isSafe()
const {
return Status == StatusTy::Safe; }
1874 bool isUnsafe()
const {
return Status == StatusTy::Unsafe; }
1877 bool isSafeWithFreeze()
const {
return Status == StatusTy::SafeWithFreeze; }
1882 Status = StatusTy::Unsafe;
1886 void freeze(IRBuilderBase &Builder, Instruction &UserI) {
1887 assert(isSafeWithFreeze() &&
1888 "should only be used when freezing is required");
1890 "UserI must be a user of ToFreeze");
1891 IRBuilder<>::InsertPointGuard Guard(Builder);
1896 if (
U.get() == ToFreeze)
1911 uint64_t NumElements = VecTy->getElementCount().getKnownMinValue();
1915 if (
C->getValue().ult(NumElements))
1916 return ScalarizationResult::safe();
1917 return ScalarizationResult::unsafe();
1922 return ScalarizationResult::unsafe();
1924 APInt Zero(IntWidth, 0);
1925 APInt MaxElts(IntWidth, NumElements);
1932 return ScalarizationResult::safe();
1933 return ScalarizationResult::unsafe();
1946 if (ValidIndices.
contains(IdxRange))
1947 return ScalarizationResult::safeWithFreeze(IdxBase);
1948 return ScalarizationResult::unsafe();
1960 C->getZExtValue() *
DL.getTypeStoreSize(ScalarType));
1972bool VectorCombine::foldSingleElementStore(Instruction &
I) {
1984 if (!
match(
SI->getValueOperand(),
1991 Value *SrcAddr =
Load->getPointerOperand()->stripPointerCasts();
1994 if (!
Load->isSimple() ||
Load->getParent() !=
SI->getParent() ||
1995 !
DL->typeSizeEqualsStoreSize(
Load->getType()->getScalarType()) ||
1996 SrcAddr !=
SI->getPointerOperand()->stripPointerCasts())
2002 auto ScalarizableIdx =
2004 if (ScalarizableIdx.isUnsafe())
2011 if (ScalarizableIdx.isSafeWithFreeze())
2014 SI->getValueOperand()->getType(),
SI->getPointerOperand(),
2015 {ConstantInt::get(Idx->getType(), 0), Idx});
2019 std::max(
SI->getAlign(),
Load->getAlign()), NewElement->
getType(), Idx,
2022 replaceValue(
I, *NSI);
2032bool VectorCombine::scalarizeLoad(Instruction &
I) {
2042 if (!LI->isSimple() || !
DL->typeSizeEqualsStoreSize(VecTy->getScalarType()))
2045 bool AllExtracts =
true;
2046 bool AllBitcasts =
true;
2048 unsigned NumInstChecked = 0;
2053 for (User *U : LI->users()) {
2055 if (!UI || UI->getParent() != LI->getParent())
2060 if (UI->use_empty())
2064 AllExtracts =
false;
2066 AllBitcasts =
false;
2070 for (Instruction &
I :
2071 make_range(std::next(LI->getIterator()), UI->getIterator())) {
2078 LastCheckedInst = UI;
2083 return scalarizeLoadExtract(LI, VecTy, Ptr);
2085 return scalarizeLoadBitcast(LI, VecTy, Ptr);
2090bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
2095 DenseMap<ExtractElementInst *, ScalarizationResult> NeedFreeze;
2098 for (
auto &Pair : NeedFreeze)
2099 Pair.second.discard();
2107 for (User *U : LI->
users()) {
2112 if (ScalarIdx.isUnsafe())
2114 if (ScalarIdx.isSafeWithFreeze()) {
2115 NeedFreeze.try_emplace(UI, ScalarIdx);
2116 ScalarIdx.discard();
2122 Index ?
Index->getZExtValue() : -1);
2130 LLVM_DEBUG(
dbgs() <<
"Found all extractions of a vector load: " << *LI
2131 <<
"\n LoadExtractCost: " << OriginalCost
2132 <<
" vs ScalarizedCost: " << ScalarizedCost <<
"\n");
2134 if (ScalarizedCost >= OriginalCost)
2141 Type *ElemType = VecTy->getElementType();
2144 for (User *U : LI->
users()) {
2146 Value *Idx = EI->getIndexOperand();
2149 auto It = NeedFreeze.find(EI);
2150 if (It != NeedFreeze.end())
2157 Builder.
CreateLoad(ElemType,
GEP, EI->getName() +
".scalar"));
2159 Align ScalarOpAlignment =
2161 NewLoad->setAlignment(ScalarOpAlignment);
2164 size_t Offset = ConstIdx->getZExtValue() *
DL->getTypeStoreSize(ElemType);
2169 replaceValue(*EI, *NewLoad,
false);
2172 FailureGuard.release();
2177bool VectorCombine::scalarizeLoadBitcast(LoadInst *LI, VectorType *VecTy,
2183 Type *TargetScalarType =
nullptr;
2184 unsigned VecBitWidth =
DL->getTypeSizeInBits(VecTy);
2186 for (User *U : LI->
users()) {
2189 Type *DestTy = BC->getDestTy();
2193 unsigned DestBitWidth =
DL->getTypeSizeInBits(DestTy);
2194 if (DestBitWidth != VecBitWidth)
2198 if (!TargetScalarType)
2199 TargetScalarType = DestTy;
2200 else if (TargetScalarType != DestTy)
2208 if (!TargetScalarType)
2216 LLVM_DEBUG(
dbgs() <<
"Found vector load feeding only bitcasts: " << *LI
2217 <<
"\n OriginalCost: " << OriginalCost
2218 <<
" vs ScalarizedCost: " << ScalarizedCost <<
"\n");
2220 if (ScalarizedCost >= OriginalCost)
2231 ScalarLoad->copyMetadata(*LI);
2234 for (User *U : LI->
users()) {
2236 replaceValue(*BC, *ScalarLoad,
false);
2242bool VectorCombine::scalarizeExtExtract(Instruction &
I) {
2257 Type *ScalarDstTy = DstTy->getElementType();
2258 if (
DL->getTypeSizeInBits(SrcTy) !=
DL->getTypeSizeInBits(ScalarDstTy))
2264 unsigned ExtCnt = 0;
2265 bool ExtLane0 =
false;
2266 for (User *U : Ext->users()) {
2280 Instruction::And, ScalarDstTy,
CostKind,
2283 (ExtCnt - ExtLane0) *
2285 Instruction::LShr, ScalarDstTy,
CostKind,
2288 if (ScalarCost > VectorCost)
2291 Value *ScalarV = Ext->getOperand(0);
2298 SmallDenseSet<ConstantInt *, 8> ExtractedLanes;
2299 bool AllExtractsTriggerUB =
true;
2300 ExtractElementInst *LastExtract =
nullptr;
2302 for (User *U : Ext->users()) {
2305 AllExtractsTriggerUB =
false;
2309 if (!LastExtract || LastExtract->
comesBefore(Extract))
2310 LastExtract = Extract;
2312 if (ExtractedLanes.
size() != DstTy->getNumElements() ||
2313 !AllExtractsTriggerUB ||
2321 uint64_t SrcEltSizeInBits =
DL->getTypeSizeInBits(SrcTy->getElementType());
2322 uint64_t TotalBits =
DL->getTypeSizeInBits(SrcTy);
2325 Value *
Mask = ConstantInt::get(PackedTy, EltBitMask);
2326 for (User *U : Ext->users()) {
2332 ? (TotalBits - SrcEltSizeInBits - Idx * SrcEltSizeInBits)
2333 : (Idx * SrcEltSizeInBits);
2336 U->replaceAllUsesWith(
And);
2344bool VectorCombine::foldConcatOfBoolMasks(Instruction &
I) {
2345 Type *Ty =
I.getType();
2350 if (
DL->isBigEndian())
2361 uint64_t ShAmtX = 0;
2369 uint64_t ShAmtY = 0;
2377 if (ShAmtX > ShAmtY) {
2385 uint64_t ShAmtDiff = ShAmtY - ShAmtX;
2386 unsigned NumSHL = (ShAmtX > 0) + (ShAmtY > 0);
2391 MaskTy->getNumElements() != ShAmtDiff ||
2392 MaskTy->getNumElements() > (
BitWidth / 2))
2397 Type::getIntNTy(Ty->
getContext(), ConcatTy->getNumElements());
2398 auto *MaskIntTy = Type::getIntNTy(Ty->
getContext(), ShAmtDiff);
2401 std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
2418 if (Ty != ConcatIntTy)
2424 LLVM_DEBUG(
dbgs() <<
"Found a concatenation of bitcasted bool masks: " <<
I
2425 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2428 if (NewCost > OldCost)
2438 if (Ty != ConcatIntTy) {
2448 replaceValue(
I, *Result);
2454bool VectorCombine::foldPermuteOfBinops(Instruction &
I) {
2455 BinaryOperator *BinOp;
2456 ArrayRef<int> OuterMask;
2464 Value *Op00, *Op01, *Op10, *Op11;
2465 ArrayRef<int> Mask0, Mask1;
2470 if (!Match0 && !Match1)
2483 if (!ShuffleDstTy || !BinOpTy || !Op0Ty || !Op1Ty)
2486 unsigned NumSrcElts = BinOpTy->getNumElements();
2491 any_of(OuterMask, [NumSrcElts](
int M) {
return M >= (int)NumSrcElts; }))
2495 SmallVector<int> NewMask0, NewMask1;
2496 for (
int M : OuterMask) {
2497 if (M < 0 || M >= (
int)NumSrcElts) {
2501 NewMask0.
push_back(Match0 ? Mask0[M] : M);
2502 NewMask1.
push_back(Match1 ? Mask1[M] : M);
2506 unsigned NumOpElts = Op0Ty->getNumElements();
2507 bool IsIdentity0 = ShuffleDstTy == Op0Ty &&
2508 all_of(NewMask0, [NumOpElts](
int M) {
return M < (int)NumOpElts; }) &&
2510 bool IsIdentity1 = ShuffleDstTy == Op1Ty &&
2511 all_of(NewMask1, [NumOpElts](
int M) {
return M < (int)NumOpElts; }) &&
2520 ShuffleDstTy, BinOpTy, OuterMask,
CostKind,
2521 0,
nullptr, {BinOp}, &
I);
2523 NewCost += BinOpCost;
2529 OldCost += Shuf0Cost;
2531 NewCost += Shuf0Cost;
2537 OldCost += Shuf1Cost;
2539 NewCost += Shuf1Cost;
2547 Op0Ty, NewMask0,
CostKind, 0,
nullptr, {Op00, Op01});
2551 Op1Ty, NewMask1,
CostKind, 0,
nullptr, {Op10, Op11});
2553 LLVM_DEBUG(
dbgs() <<
"Found a shuffle feeding a shuffled binop: " <<
I
2554 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2558 if (NewCost > OldCost)
2569 NewInst->copyIRFlags(BinOp);
2573 replaceValue(
I, *NewBO);
2579bool VectorCombine::foldShuffleOfBinops(Instruction &
I) {
2580 ArrayRef<int> OldMask;
2587 if (
LHS->getOpcode() !=
RHS->getOpcode())
2591 bool IsCommutative =
false;
2600 IsCommutative = BinaryOperator::isCommutative(BO->getOpcode());
2611 if (!ShuffleDstTy || !BinResTy || !BinOpTy ||
X->getType() !=
Z->getType())
2614 bool SameBinOp =
LHS ==
RHS;
2615 unsigned NumSrcElts = BinOpTy->getNumElements();
2618 if (IsCommutative &&
X != Z &&
Y != W && (
X == W ||
Y == Z))
2621 auto ConvertToUnary = [NumSrcElts](
int &
M) {
2622 if (M >= (
int)NumSrcElts)
2626 SmallVector<int> NewMask0(OldMask);
2635 SmallVector<int> NewMask1(OldMask);
2654 ShuffleDstTy, BinResTy, OldMask,
CostKind, 0,
2664 ArrayRef<int> InnerMask;
2666 m_Mask(InnerMask)))) &&
2669 [NumSrcElts](
int M) {
return M < (int)NumSrcElts; })) {
2681 bool ReducedInstCount =
false;
2682 ReducedInstCount |= MergeInner(
X, 0, NewMask0,
CostKind);
2683 ReducedInstCount |= MergeInner(
Y, 0, NewMask1,
CostKind);
2684 ReducedInstCount |= MergeInner(Z, NumSrcElts, NewMask0,
CostKind);
2685 ReducedInstCount |= MergeInner(W, NumSrcElts, NewMask1,
CostKind);
2686 bool SingleSrcBinOp = (
X ==
Y) && (Z == W) && (NewMask0 == NewMask1);
2698 I.getType()->getScalarType()->isIntegerTy(1) &&
2702 auto *ShuffleCmpTy =
2705 SK0, ShuffleCmpTy, BinOpTy, NewMask0,
CostKind, 0,
nullptr, {
X,
Z});
2706 if (!SingleSrcBinOp)
2716 PredLHS,
CostKind, Op0Info, Op1Info);
2726 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2733 if (ReducedInstCount ? (NewCost > OldCost) : (NewCost >= OldCost))
2742 : Builder.
CreateCmp(PredLHS, Shuf0, Shuf1);
2746 NewInst->copyIRFlags(
LHS);
2747 NewInst->andIRFlags(
RHS);
2752 replaceValue(
I, *NewBO);
2759bool VectorCombine::foldShuffleOfSelects(Instruction &
I) {
2761 Value *C1, *
T1, *F1, *C2, *T2, *F2;
2772 if (!C1VecTy || !C2VecTy || C1VecTy != C2VecTy)
2778 if (((SI0FOp ==
nullptr) != (SI1FOp ==
nullptr)) ||
2779 ((SI0FOp !=
nullptr) &&
2780 (SI0FOp->getFastMathFlags() != SI1FOp->getFastMathFlags())))
2786 auto SelOp = Instruction::Select;
2794 CostSel1 + CostSel2 +
2796 {
I.getOperand(0),
I.getOperand(1)}, &
I);
2800 Mask,
CostKind, 0,
nullptr, {C1, C2});
2810 if (!Sel1->hasOneUse())
2811 NewCost += CostSel1;
2812 if (!Sel2->hasOneUse())
2813 NewCost += CostSel2;
2816 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2818 if (NewCost > OldCost)
2827 NewSel = Builder.
CreateSelectFMF(ShuffleCmp, ShuffleTrue, ShuffleFalse,
2828 SI0FOp->getFastMathFlags());
2830 NewSel = Builder.
CreateSelect(ShuffleCmp, ShuffleTrue, ShuffleFalse);
2835 replaceValue(
I, *NewSel);
2841bool VectorCombine::foldShuffleOfCastops(Instruction &
I) {
2843 ArrayRef<int> OldMask;
2852 if (!C0 || (IsBinaryShuffle && !C1))
2859 if (!IsBinaryShuffle && Opcode == Instruction::BitCast)
2862 if (IsBinaryShuffle) {
2863 if (C0->getSrcTy() != C1->getSrcTy())
2866 if (Opcode != C1->getOpcode()) {
2868 Opcode = Instruction::SExt;
2877 if (!ShuffleDstTy || !CastDstTy || !CastSrcTy)
2880 unsigned NumSrcElts = CastSrcTy->getNumElements();
2881 unsigned NumDstElts = CastDstTy->getNumElements();
2882 assert((NumDstElts == NumSrcElts || Opcode == Instruction::BitCast) &&
2883 "Only bitcasts expected to alter src/dst element counts");
2887 if (NumDstElts != NumSrcElts && (NumSrcElts % NumDstElts) != 0 &&
2888 (NumDstElts % NumSrcElts) != 0)
2891 SmallVector<int, 16> NewMask;
2892 if (NumSrcElts >= NumDstElts) {
2895 assert(NumSrcElts % NumDstElts == 0 &&
"Unexpected shuffle mask");
2896 unsigned ScaleFactor = NumSrcElts / NumDstElts;
2901 assert(NumDstElts % NumSrcElts == 0 &&
"Unexpected shuffle mask");
2902 unsigned ScaleFactor = NumDstElts / NumSrcElts;
2907 auto *NewShuffleDstTy =
2916 if (IsBinaryShuffle)
2931 if (IsBinaryShuffle) {
2941 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2943 if (NewCost > OldCost)
2947 if (IsBinaryShuffle)
2957 NewInst->copyIRFlags(C0);
2958 if (IsBinaryShuffle)
2959 NewInst->andIRFlags(C1);
2963 replaceValue(
I, *Cast);
2973bool VectorCombine::foldShuffleOfShuffles(Instruction &
I) {
2974 ArrayRef<int> OuterMask;
2975 Value *OuterV0, *OuterV1;
2980 ArrayRef<int> InnerMask0, InnerMask1;
2981 Value *X0, *X1, *Y0, *Y1;
2986 if (!Match0 && !Match1)
2991 SmallVector<int, 16> PoisonMask1;
2996 InnerMask1 = PoisonMask1;
3000 X0 = Match0 ? X0 : OuterV0;
3001 Y0 = Match0 ? Y0 : OuterV0;
3002 X1 = Match1 ? X1 : OuterV1;
3003 Y1 = Match1 ? Y1 : OuterV1;
3007 if (!ShuffleDstTy || !ShuffleSrcTy || !ShuffleImmTy ||
3011 unsigned NumSrcElts = ShuffleSrcTy->getNumElements();
3012 unsigned NumImmElts = ShuffleImmTy->getNumElements();
3017 SmallVector<int, 16> NewMask(OuterMask);
3018 Value *NewX =
nullptr, *NewY =
nullptr;
3019 for (
int &M : NewMask) {
3020 Value *Src =
nullptr;
3021 if (0 <= M && M < (
int)NumImmElts) {
3025 Src =
M >= (int)NumSrcElts ? Y0 : X0;
3026 M =
M >= (int)NumSrcElts ? (M - NumSrcElts) :
M;
3028 }
else if (M >= (
int)NumImmElts) {
3033 Src =
M >= (int)NumSrcElts ? Y1 : X1;
3034 M =
M >= (int)NumSrcElts ? (M - NumSrcElts) :
M;
3038 assert(0 <= M && M < (
int)NumSrcElts &&
"Unexpected shuffle mask index");
3047 if (!NewX || NewX == Src) {
3051 if (!NewY || NewY == Src) {
3070 replaceValue(
I, *NewX);
3087 bool IsUnary =
all_of(NewMask, [&](
int M) {
return M < (int)NumSrcElts; });
3093 nullptr, {NewX, NewY});
3095 NewCost += InnerCost0;
3097 NewCost += InnerCost1;
3100 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
3102 if (NewCost > OldCost)
3106 replaceValue(
I, *Shuf);
3122bool VectorCombine::foldShufflesOfLengthChangingShuffles(Instruction &
I) {
3127 unsigned ChainLength = 0;
3128 SmallVector<int>
Mask;
3129 SmallVector<int> YMask;
3139 ArrayRef<int> OuterMask;
3140 Value *OuterV0, *OuterV1;
3141 if (ChainLength != 0 && !Trunk->
hasOneUse())
3144 m_Mask(OuterMask))))
3146 if (OuterV0->
getType() != TrunkType) {
3152 ArrayRef<int> InnerMask0, InnerMask1;
3158 bool Match0Leaf = Match0 && A0->
getType() !=
I.getType();
3159 bool Match1Leaf = Match1 && A1->
getType() !=
I.getType();
3160 if (Match0Leaf == Match1Leaf) {
3166 SmallVector<int> CommutedOuterMask;
3173 for (
int &M : CommutedOuterMask) {
3176 if (M < (
int)NumTrunkElts)
3181 OuterMask = CommutedOuterMask;
3200 int NumLeafElts = YType->getNumElements();
3201 SmallVector<int> LocalYMask(InnerMask1);
3202 for (
int &M : LocalYMask) {
3203 if (M >= NumLeafElts)
3213 Mask.assign(OuterMask);
3214 YMask.
assign(LocalYMask);
3215 OldCost = NewCost = LocalOldCost;
3222 SmallVector<int> NewYMask(YMask);
3224 for (
auto [CombinedM, LeafM] :
llvm::zip(NewYMask, LocalYMask)) {
3225 if (LeafM == -1 || CombinedM == LeafM)
3227 if (CombinedM == -1) {
3237 SmallVector<int> NewMask;
3238 NewMask.
reserve(NumTrunkElts);
3239 for (
int M : Mask) {
3240 if (M < 0 || M >=
static_cast<int>(NumTrunkElts))
3255 if (LocalNewCost >= NewCost && LocalOldCost < LocalNewCost - NewCost)
3259 if (ChainLength == 1) {
3260 dbgs() <<
"Found chain of shuffles fed by length-changing shuffles: "
3263 dbgs() <<
" next chain link: " << *Trunk <<
'\n'
3264 <<
" old cost: " << (OldCost + LocalOldCost)
3265 <<
" new cost: " << LocalNewCost <<
'\n';
3270 OldCost += LocalOldCost;
3271 NewCost = LocalNewCost;
3275 if (ChainLength <= 1)
3283 return M < 0 || M >=
static_cast<int>(NumTrunkElts);
3286 for (
int &M : Mask) {
3287 if (M >=
static_cast<int>(NumTrunkElts))
3288 M = YMask[
M - NumTrunkElts];
3292 replaceValue(
I, *Root);
3299 replaceValue(
I, *Root);
3305bool VectorCombine::foldShuffleOfIntrinsics(Instruction &
I) {
3307 ArrayRef<int> OldMask;
3317 if (IID != II1->getIntrinsicID())
3326 if (!ShuffleDstTy || !II0Ty)
3332 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3333 Value *Arg0 = II0->getArgOperand(
I);
3334 Value *Arg1 = II1->getArgOperand(
I);
3351 II0Ty, OldMask,
CostKind, 0,
nullptr, {II0, II1}, &
I);
3355 SmallDenseSet<std::pair<Value *, Value *>> SeenOperandPairs;
3356 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3358 NewArgsTy.
push_back(II0->getArgOperand(
I)->getType());
3362 ShuffleDstTy->getNumElements());
3364 std::pair<Value *, Value *> OperandPair =
3365 std::make_pair(II0->getArgOperand(
I), II1->getArgOperand(
I));
3366 if (!SeenOperandPairs.
insert(OperandPair).second) {
3372 CostKind, 0,
nullptr, {II0->getArgOperand(
I), II1->getArgOperand(
I)});
3375 IntrinsicCostAttributes NewAttr(IID, ShuffleDstTy, NewArgsTy);
3378 if (!II0->hasOneUse())
3380 if (II1 != II0 && !II1->hasOneUse())
3384 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
3387 if (NewCost > OldCost)
3391 SmallDenseMap<std::pair<Value *, Value *>,
Value *> ShuffleCache;
3392 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I)
3396 std::pair<Value *, Value *> OperandPair =
3397 std::make_pair(II0->getArgOperand(
I), II1->getArgOperand(
I));
3398 auto It = ShuffleCache.
find(OperandPair);
3399 if (It != ShuffleCache.
end()) {
3405 II1->getArgOperand(
I), OldMask);
3406 ShuffleCache[OperandPair] = Shuf;
3414 NewInst->copyIRFlags(II0);
3415 NewInst->andIRFlags(II1);
3418 replaceValue(
I, *NewIntrinsic);
3424bool VectorCombine::foldPermuteOfIntrinsic(Instruction &
I) {
3436 if (!ShuffleDstTy || !IntrinsicSrcTy)
3440 unsigned NumSrcElts = IntrinsicSrcTy->getNumElements();
3441 if (
any_of(Mask, [NumSrcElts](
int M) {
return M >= (int)NumSrcElts; }))
3454 IntrinsicSrcTy, Mask,
CostKind, 0,
nullptr, {V0}, &
I);
3458 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3460 NewArgsTy.
push_back(II0->getArgOperand(
I)->getType());
3464 ShuffleDstTy->getNumElements());
3467 ArgTy, VecTy, Mask,
CostKind, 0,
nullptr,
3468 {II0->getArgOperand(
I)});
3471 IntrinsicCostAttributes NewAttr(IID, ShuffleDstTy, NewArgsTy);
3476 if (!II0->hasOneUse())
3479 LLVM_DEBUG(
dbgs() <<
"Found a permute of intrinsic: " <<
I <<
"\n OldCost: "
3480 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
3482 if (NewCost > OldCost)
3487 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3500 NewInst->copyIRFlags(II0);
3502 replaceValue(
I, *NewIntrinsic);
3512 int M = SV->getMaskValue(Lane);
3515 if (
static_cast<unsigned>(M) < NumElts) {
3516 V = SV->getOperand(0);
3519 V = SV->getOperand(1);
3530 auto [U, Lane] = IL;
3543 unsigned NumElts = Ty->getNumElements();
3544 if (Item.
size() == NumElts || NumElts == 1 || Item.
size() % NumElts != 0)
3550 std::iota(ConcatMask.
begin(), ConcatMask.
end(), 0);
3556 unsigned NumSlices = Item.
size() / NumElts;
3561 for (
unsigned Slice = 0; Slice < NumSlices; ++Slice) {
3562 Value *SliceV = Item[Slice * NumElts].first;
3563 if (!SliceV || SliceV->
getType() != Ty)
3565 for (
unsigned Elt = 0; Elt < NumElts; ++Elt) {
3566 auto [V, Lane] = Item[Slice * NumElts + Elt];
3567 if (Lane !=
static_cast<int>(Elt) || SliceV != V)
3576 const DenseSet<std::pair<Value *, Use *>> &IdentityLeafs,
3577 const DenseSet<std::pair<Value *, Use *>> &SplatLeafs,
3578 const DenseSet<std::pair<Value *, Use *>> &ConcatLeafs,
3581 auto [FrontV, FrontLane] = Item.
front();
3583 if (IdentityLeafs.contains(std::make_pair(FrontV, From))) {
3586 if (SplatLeafs.contains(std::make_pair(FrontV, From))) {
3588 return Builder.CreateShuffleVector(FrontV, Mask);
3590 if (ConcatLeafs.contains(std::make_pair(FrontV, From))) {
3594 for (
unsigned S = 0; S <
Values.size(); ++S)
3595 Values[S] = Item[S * NumElts].first;
3597 while (
Values.size() > 1) {
3600 std::iota(Mask.begin(), Mask.end(), 0);
3602 for (
unsigned S = 0; S < NewValues.
size(); ++S)
3604 Builder.CreateShuffleVector(
Values[S * 2],
Values[S * 2 + 1], Mask);
3618 if (BCDstTy && BCSrcTy &&
3619 BCDstTy->getElementCount() != BCSrcTy->getElementCount()) {
3620 unsigned DstElts = BCDstTy->getNumElements();
3621 unsigned SrcElts = BCSrcTy->getNumElements();
3623 if (DstElts > SrcElts) {
3625 unsigned R = DstElts / SrcElts;
3626 if (Item.
size() % R != 0)
3628 for (
unsigned Idx = 0,
E = Item.
size(); Idx <
E; Idx += R) {
3629 auto [V, Lane] = Item[Idx];
3639 unsigned R = SrcElts / DstElts;
3640 for (
auto [V, Lane] : Item) {
3646 for (
unsigned J = 0; J < R; ++J)
3651 IdentityLeafs, SplatLeafs, ConcatLeafs,
3652 Builder, WorkList,
TTI);
3654 return Builder.CreateBitCast(
3659 unsigned NumOps =
I->getNumOperands() - (
II ? 1 : 0);
3661 for (
unsigned Idx = 0; Idx <
NumOps; Idx++) {
3664 Ops[Idx] =
II->getOperand(Idx);
3669 IdentityLeafs, SplatLeafs, ConcatLeafs, Builder, WorkList,
TTI);
3679 for (
const auto &Lane : Item)
3692 auto *
Value = Builder.CreateCmp(CI->getPredicate(),
Ops[0],
Ops[1]);
3702 auto *
Value = Builder.CreateCast(CI->getOpcode(),
Ops[0], DstTy);
3707 auto *
Value = Builder.CreateIntrinsic(DstTy,
II->getIntrinsicID(),
Ops);
3721bool VectorCombine::foldShuffleToIdentity(Instruction &
I) {
3723 if (!Ty ||
I.use_empty())
3727 for (
unsigned M = 0,
E = Ty->getNumElements(); M <
E; ++M)
3731 Candidates.
push_back(std::make_pair(Start, &*
I.use_begin()));
3732 DenseSet<std::pair<Value *, Use *>> IdentityLeafs, SplatLeafs, ConcatLeafs;
3733 unsigned NumVisited = 0;
3734 bool TraversedElCountChangingBitcast =
false;
3736 while (!Candidates.
empty()) {
3741 auto Item = ItemFrom.first;
3742 auto From = ItemFrom.second;
3743 auto [FrontV, FrontLane] = Item.front();
3750 if (FrontLane == 0 &&
3754 Value *FrontV = Item.front().first;
3756 E.value().second == (int)
E.index());
3758 IdentityLeafs.
insert(std::make_pair(FrontV, From));
3763 C &&
C->getSplatValue() &&
3765 Value *FrontV = Item.front().first;
3771 SplatLeafs.
insert(std::make_pair(FrontV, From));
3776 auto [FrontV, FrontLane] = Item.front();
3777 auto [
V, Lane] = IL;
3778 return !
V || (
V == FrontV && Lane == FrontLane);
3780 SplatLeafs.
insert(std::make_pair(FrontV, From));
3786 auto CheckLaneIsEquivalentToFirst = [Item](
InstLane IL) {
3787 Value *FrontV = Item.front().first;
3796 if (CI->getPredicate() !=
cast<CmpInst>(FrontV)->getPredicate())
3799 if (CI->getSrcTy()->getScalarType() !=
3804 SI->getOperand(0)->getType() !=
3811 II->getIntrinsicID() ==
3813 !
II->hasOperandBundles());
3820 BO && BO->isIntDivRem())
3827 }
else if (
isa<UnaryOperator, TruncInst, ZExtInst, SExtInst, FPToSIInst,
3828 FPToUIInst, SIToFPInst, UIToFPInst>(FrontV)) {
3835 if (BCDstTy && BCSrcTy) {
3836 ElementCount DstEC = BCDstTy->getElementCount();
3837 ElementCount SrcEC = BCSrcTy->getElementCount();
3838 if (DstEC == SrcEC) {
3841 &BitCast->getOperandUse(0));
3846 if (DstElts > SrcElts && DstElts % SrcElts == 0) {
3850 unsigned R = DstElts / SrcElts;
3852 bool Valid = Item.size() %
R == 0;
3853 for (
unsigned Idx = 0,
E = Item.size(); Valid && Idx <
E;
3855 auto [V0, L0] = Item[Idx];
3858 [](
InstLane IL) {
return IL.first !=
nullptr; })) {
3869 for (
unsigned J = 1; J <
R; ++J) {
3870 auto [VJ, LJ] = Item[Idx + J];
3871 if (!VJ || VJ != V0 || LJ != L0 + (
int)J) {
3882 TraversedElCountChangingBitcast =
true;
3883 Candidates.
emplace_back(NItem, &BitCast->getOperandUse(0));
3886 }
else if (SrcElts > DstElts && SrcElts % DstElts == 0) {
3889 unsigned R = SrcElts / DstElts;
3891 for (
auto [V, Lane] : Item) {
3897 for (
unsigned J = 0; J <
R; ++J)
3900 TraversedElCountChangingBitcast =
true;
3901 Candidates.
emplace_back(NItem, &BitCast->getOperandUse(0));
3907 &Sel->getOperandUse(0));
3909 &Sel->getOperandUse(1));
3911 &Sel->getOperandUse(2));
3915 !
II->hasOperandBundles()) {
3916 for (
unsigned Op = 0,
E =
II->getNumOperands() - 1;
Op <
E;
Op++) {
3920 Value *FrontV = Item.front().first;
3937 ConcatLeafs.
insert(std::make_pair(FrontV, From));
3944 if (NumVisited <= 1)
3950 if (NumVisited == 2 && TraversedElCountChangingBitcast)
3953 LLVM_DEBUG(
dbgs() <<
"Found a superfluous identity shuffle: " <<
I <<
"\n");
3960 ConcatLeafs, Builder, Worklist, &
TTI);
3961 replaceValue(
I, *V);
3968bool VectorCombine::foldShuffleFromReductions(Instruction &
I) {
3972 switch (
II->getIntrinsicID()) {
3973 case Intrinsic::vector_reduce_add:
3974 case Intrinsic::vector_reduce_mul:
3975 case Intrinsic::vector_reduce_and:
3976 case Intrinsic::vector_reduce_or:
3977 case Intrinsic::vector_reduce_xor:
3978 case Intrinsic::vector_reduce_smin:
3979 case Intrinsic::vector_reduce_smax:
3980 case Intrinsic::vector_reduce_umin:
3981 case Intrinsic::vector_reduce_umax:
3990 std::queue<Value *> Worklist;
3991 SmallPtrSet<Value *, 4> Visited;
3992 ShuffleVectorInst *Shuffle =
nullptr;
3996 while (!Worklist.empty()) {
3997 Value *CV = Worklist.front();
4009 if (CI->isBinaryOp()) {
4010 for (
auto *
Op : CI->operand_values())
4014 if (Shuffle && Shuffle != SV)
4031 for (
auto *V : Visited)
4032 for (
auto *U :
V->users())
4033 if (!Visited.contains(U) && U != &
I)
4036 FixedVectorType *VecType =
4040 FixedVectorType *ShuffleInputType =
4042 if (!ShuffleInputType)
4048 SmallVector<int> ConcatMask;
4050 sort(ConcatMask, [](
int X,
int Y) {
return (
unsigned)
X < (unsigned)
Y; });
4051 bool UsesSecondVec =
4052 any_of(ConcatMask, [&](
int M) {
return M >= (int)NumInputElts; });
4059 ShuffleInputType, ConcatMask,
CostKind);
4061 LLVM_DEBUG(
dbgs() <<
"Found a reduction feeding from a shuffle: " << *Shuffle
4063 LLVM_DEBUG(
dbgs() <<
" OldCost: " << OldCost <<
" vs NewCost: " << NewCost
4065 bool MadeChanges =
false;
4066 if (NewCost < OldCost) {
4070 LLVM_DEBUG(
dbgs() <<
"Created new shuffle: " << *NewShuffle <<
"\n");
4071 replaceValue(*Shuffle, *NewShuffle);
4077 MadeChanges |= foldSelectShuffle(*Shuffle,
true);
4098bool VectorCombine::foldShuffleChainsToReduce(Instruction &
I) {
4107 if (FVT->getNumElements() < 2)
4110 std::optional<Instruction::BinaryOps> CommonBinOp;
4111 std::optional<Intrinsic::ID> CommonCallOp;
4116 CommonBinOp = BO->getOpcode();
4118 CommonCallOp = MMI->getIntrinsicID();
4124 FastMathFlags CommonFMF;
4125 bool IsFloatReduction =
false;
4129 auto IsChainNode = [&](
Value *
V) {
4131 return CommonBinOp && BO->getOpcode() == *CommonBinOp;
4133 return CommonCallOp && MMI->getIntrinsicID() == *CommonCallOp;
4141 constexpr unsigned MaxChainNodes = 32;
4142 SmallSetVector<Value *, 16> Nodes;
4143 SmallSetVector<Value *, 4> Sources;
4144 unsigned NumVisited = 0;
4145 auto AddSource = [&](
Value *
V) {
4151 auto Walk = [&](
Value *
V,
auto &&Walk) ->
bool {
4154 if (++NumVisited > MaxChainNodes)
4156 if (!IsChainNode(V))
4157 return AddSource(V);
4162 if (!Walk(
U->getOperand(
I), Walk))
4171 return AddSource(V);
4173 if (!Walk(VecOpEE, Walk) || Nodes.
empty())
4180 for (
Value *V : Nodes) {
4186 if (!IsFloatReduction) {
4188 IsFloatReduction =
true;
4202 DenseMap<Value *, Demand> Demands;
4203 auto DemandOf = [&](
Value *
V) -> Demand & {
4205 Demand &
D = Demands[
V];
4206 if (
D.Lanes.getBitWidth() !=
N)
4210 DemandOf(VecOpEE).Lanes.setBit(0);
4212 Demand DV = Demands.
lookup(V);
4213 if (DV.Lanes.isZero())
4216 ArrayRef<int>
Mask = SVI->getShuffleMask();
4217 Demand &
DS = DemandOf(SVI->getOperand(0));
4218 for (
unsigned I = 0,
E =
Mask.size();
I !=
E; ++
I) {
4220 if (!DV.Lanes[
I] || Mask[
I] < 0 ||
4221 (
unsigned)Mask[
I] >=
DS.Lanes.getBitWidth())
4223 if (
DS.Lanes[Mask[
I]] || DV.Duplicates[
I])
4224 DS.Duplicates.setBit(Mask[
I]);
4225 DS.Lanes.setBit(Mask[
I]);
4229 for (
Value *
Op : {
U->getOperand(0),
U->getOperand(1)}) {
4230 Demand &DOp = DemandOf(
Op);
4232 DOp.Duplicates |= DV.Duplicates | (DOp.Lanes & DV.Lanes);
4233 DOp.Lanes |= DV.Lanes;
4240 auto CoversChain = [&](
Value *
V) {
4241 SmallVector<Value *, 8> Worklist(1, VecOpEE);
4242 SmallPtrSet<Value *, 8> Seen;
4244 while (!Worklist.empty()) {
4247 for (
unsigned I = 0;
I !=
NumOps; ++
I) {
4251 if (!Nodes.contains(
Op))
4253 Worklist.push_back(
Op);
4261 struct ReductionCut {
4265 std::optional<ReductionCut> Cut;
4266 for (
Value *S : Sources) {
4267 auto It = Demands.
find(S);
4268 if (It == Demands.
end() || It->second.Lanes.isZero())
4270 if (!IsIdempotent && !It->second.Duplicates.isZero()) {
4275 Cut = ReductionCut{S, It->second.Lanes};
4282 if (!IsIdempotent && !(Cut->Elts & It->second.Lanes).isZero()) {
4286 Cut->Elts |= It->second.Lanes;
4289 for (
Value *V : Nodes) {
4292 auto It = Demands.
find(V);
4293 if (It == Demands.
end() || !It->second.Lanes.isAllOnes())
4295 if (!IsIdempotent && !It->second.Duplicates.isZero())
4297 if (!CoversChain(V))
4299 Cut = ReductionCut{
V, It->second.Lanes};
4304 if (!Cut || Cut->Elts.popcount() < 2)
4314 for (
Value *V : Nodes)
4318 bool IsPartialReduction = !Cut->Elts.isAllOnes();
4319 FixedVectorType *ReduceVecTy =
4324 SmallVector<int> ExtractMask;
4326 if (IsPartialReduction) {
4327 for (
unsigned I = 0,
E = Cut->Elts.getBitWidth();
I !=
E; ++
I)
4329 ExtractMask.push_back(
I);
4330 unsigned SubIdx = 0, SubLen;
4331 auto SK = Cut->Elts.isShiftedMask(SubIdx, SubLen)
4335 SubIdx, ReduceVecTy);
4338 IntrinsicCostAttributes ICA(
4339 ReducedOp, ReduceVecTy->getElementType(),
4343 IsFloatReduction ? CommonFMF : FastMathFlags());
4346 LLVM_DEBUG(
dbgs() <<
"Found reduction shuffle chain: " <<
I <<
"\n OldCost : "
4347 << OrigCost <<
" vs NewCost: " << NewCost <<
"\n");
4352 if (VecOpEE->
hasOneUse() ? (NewCost > OrigCost) : (NewCost >= OrigCost))
4355 Value *ReduceInput = Cut->Src;
4356 if (IsPartialReduction)
4359 Value *ReducedResult;
4360 if (IsFloatReduction) {
4362 *CommonBinOp, ReduceVecTy->getElementType(),
false,
4365 {Identity, ReduceInput}, CommonFMF);
4370 replaceValue(
I, *ReducedResult);
4379bool VectorCombine::foldCastFromReductions(Instruction &
I) {
4384 bool TruncOnly =
false;
4387 case Intrinsic::vector_reduce_add:
4388 case Intrinsic::vector_reduce_mul:
4391 case Intrinsic::vector_reduce_and:
4392 case Intrinsic::vector_reduce_or:
4393 case Intrinsic::vector_reduce_xor:
4400 Value *ReductionSrc =
I.getOperand(0);
4412 Type *ResultTy =
I.getType();
4415 ReductionOpc, ReductionSrcTy, std::nullopt,
CostKind);
4425 if (OldCost <= NewCost || !NewCost.
isValid())
4429 II->getIntrinsicID(), {Src});
4431 replaceValue(
I, *NewCast);
4459bool VectorCombine::foldSignBitReductionCmp(Instruction &
I) {
4461 IntrinsicInst *ReduceOp;
4462 const APInt *CmpVal;
4469 case Intrinsic::vector_reduce_or:
4470 case Intrinsic::vector_reduce_umax:
4471 case Intrinsic::vector_reduce_and:
4472 case Intrinsic::vector_reduce_umin:
4473 case Intrinsic::vector_reduce_add:
4484 unsigned BitWidth = VecTy->getScalarSizeInBits();
4488 unsigned NumElts = VecTy->getNumElements();
4497 case Intrinsic::vector_reduce_or:
4498 case Intrinsic::vector_reduce_umax:
4499 TreeOpcode = Instruction::Or;
4501 case Intrinsic::vector_reduce_and:
4502 case Intrinsic::vector_reduce_umin:
4503 TreeOpcode = Instruction::And;
4505 case Intrinsic::vector_reduce_add:
4506 TreeOpcode = Instruction::Add;
4514 SmallVector<Value *, 8> Worklist;
4515 SmallVector<Value *, 8> Sources;
4517 std::optional<bool> IsAShr;
4518 constexpr unsigned MaxSources = 8;
4523 while (!Worklist.
empty() && Worklist.
size() <= MaxSources &&
4524 Sources.
size() <= MaxSources) {
4533 bool ThisIsAShr = Shr->getOpcode() == Instruction::AShr;
4535 IsAShr = ThisIsAShr;
4536 else if (*IsAShr != ThisIsAShr)
4562 if (Sources.
empty() || Sources.
size() > MaxSources ||
4563 Worklist.
size() > MaxSources || !IsAShr)
4566 unsigned NumSources = Sources.
size();
4570 if (OrigIID == Intrinsic::vector_reduce_add &&
4578 (OrigIID == Intrinsic::vector_reduce_add) ? NumSources * NumElts : 1;
4581 NegativeVal.negate();
4613 TestsNegative =
false;
4614 }
else if (*CmpVal == NegativeVal) {
4615 TestsNegative =
true;
4619 IsEq = Pred == ICmpInst::ICMP_EQ;
4620 }
else if (Pred == ICmpInst::ICMP_SLT && *CmpVal == RangeHigh) {
4622 TestsNegative = (RangeHigh == NegativeVal);
4623 }
else if (Pred == ICmpInst::ICMP_SGT && *CmpVal == RangeHigh - 1) {
4625 TestsNegative = (RangeHigh == NegativeVal);
4626 }
else if (Pred == ICmpInst::ICMP_SGT && *CmpVal == RangeLow) {
4628 TestsNegative = (RangeLow == NegativeVal);
4629 }
else if (Pred == ICmpInst::ICMP_SLT && *CmpVal == RangeLow + 1) {
4631 TestsNegative = (RangeLow == NegativeVal);
4674 enum CheckKind :
unsigned {
4681 auto RequiresOr = [](CheckKind
C) ->
bool {
return C & 0b100; };
4683 auto IsNegativeCheck = [](CheckKind
C) ->
bool {
return C & 0b010; };
4685 auto Invert = [](CheckKind
C) {
return CheckKind(
C ^ 0b011); };
4689 case Intrinsic::vector_reduce_or:
4690 case Intrinsic::vector_reduce_umax:
4691 Base = TestsNegative ? AnyNeg : AllNonNeg;
4693 case Intrinsic::vector_reduce_and:
4694 case Intrinsic::vector_reduce_umin:
4695 Base = TestsNegative ? AllNeg : AnyNonNeg;
4697 case Intrinsic::vector_reduce_add:
4698 Base = TestsNegative ? AllNeg : AllNonNeg;
4713 return ArithCost <= MinMaxCost ? std::make_pair(Arith, ArithCost)
4714 : std::make_pair(MinMax, MinMaxCost);
4718 auto [NewIID, NewCost] = RequiresOr(
Check)
4719 ? PickCheaper(Intrinsic::vector_reduce_or,
4720 Intrinsic::vector_reduce_umax)
4721 : PickCheaper(
Intrinsic::vector_reduce_and,
4725 if (NumSources > 1) {
4726 unsigned CombineOpc =
4727 RequiresOr(
Check) ? Instruction::Or : Instruction::And;
4732 LLVM_DEBUG(
dbgs() <<
"Found sign-bit reduction cmp: " <<
I <<
"\n OldCost: "
4733 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
4735 if (NewCost > OldCost)
4740 Type *ScalarTy = VecTy->getScalarType();
4743 if (NumSources == 1) {
4754 replaceValue(
I, *NewCmp);
4785bool VectorCombine::foldReductionZeroTest(Instruction &
I) {
4794 if (!
II || !
II->hasOneUse())
4797 auto ReduceID =
II->getIntrinsicID();
4798 if (ReduceID != Intrinsic::vector_reduce_or &&
4799 ReduceID != Intrinsic::vector_reduce_umax)
4802 Value *Vec =
II->getArgOperand(0);
4804 if (!VecTy || !VecTy->getElementType()->isIntegerTy())
4809 ? Intrinsic::vector_reduce_or
4824 LLVM_DEBUG(
dbgs() <<
"Found a reduction zero test: " <<
I <<
"\n OldCost: "
4825 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
4827 if (!OldCost.
isValid() || !NewCost.
isValid() || NewCost > OldCost)
4833 replaceValue(
I, *NewReduce);
4858bool VectorCombine::foldICmpEqZeroVectorReduce(Instruction &
I) {
4869 switch (
II->getIntrinsicID()) {
4870 case Intrinsic::vector_reduce_add:
4871 case Intrinsic::vector_reduce_or:
4872 case Intrinsic::vector_reduce_umin:
4873 case Intrinsic::vector_reduce_umax:
4874 case Intrinsic::vector_reduce_smin:
4875 case Intrinsic::vector_reduce_smax:
4881 Value *InnerOp =
II->getArgOperand(0);
4924 switch (
II->getIntrinsicID()) {
4925 case Intrinsic::vector_reduce_add: {
4930 unsigned NumElems = XTy->getNumElements();
4936 if (LeadingZerosX <= LostBits || LeadingZerosFX <= LostBits)
4944 case Intrinsic::vector_reduce_smin:
4945 case Intrinsic::vector_reduce_smax:
4955 LLVM_DEBUG(
dbgs() <<
"Found a reduction to 0 comparison with removable op: "
4971 case Intrinsic::vector_reduce_add:
4972 case Intrinsic::vector_reduce_or:
4978 case Intrinsic::vector_reduce_umin:
4979 case Intrinsic::vector_reduce_umax:
4980 case Intrinsic::vector_reduce_smin:
4981 case Intrinsic::vector_reduce_smax:
4993 NewReduceCost + (InnerOp->
hasOneUse() ? 0 : ExtCost);
4995 LLVM_DEBUG(
dbgs() <<
"Found a removable extension before reduction: "
4996 << *InnerOp <<
"\n OldCost: " << OldCost
4997 <<
" vs NewCost: " << NewCost <<
"\n");
5003 if (NewCost > OldCost)
5012 Builder.
CreateICmp(Pred, NewReduce, ConstantInt::getNullValue(Ty));
5013 replaceValue(
I, *NewCmp);
5044bool VectorCombine::foldEquivalentReductionCmp(Instruction &
I) {
5047 const APInt *CmpVal;
5052 if (!
II || !
II->hasOneUse())
5055 const auto IsValidOrUmaxCmp = [&]() {
5064 bool IsPositive = CmpVal->
isAllOnes() && Pred == ICmpInst::ICMP_SGT;
5066 bool IsNegative = (CmpVal->
isZero() || CmpVal->
isOne() || *CmpVal == 2) &&
5067 Pred == ICmpInst::ICMP_SLT;
5068 return IsEquality || IsPositive || IsNegative;
5071 const auto IsValidAndUminCmp = [&]() {
5076 const auto LeadingOnes = CmpVal->
countl_one();
5083 bool IsNegative = CmpVal->
isZero() && Pred == ICmpInst::ICMP_SLT;
5092 ((*CmpVal)[0] || (*CmpVal)[1]) && Pred == ICmpInst::ICMP_SGT;
5093 return IsEquality || IsNegative || IsPositive;
5101 switch (OriginalIID) {
5102 case Intrinsic::vector_reduce_or:
5103 if (!IsValidOrUmaxCmp())
5105 AlternativeIID = Intrinsic::vector_reduce_umax;
5107 case Intrinsic::vector_reduce_umax:
5108 if (!IsValidOrUmaxCmp())
5110 AlternativeIID = Intrinsic::vector_reduce_or;
5112 case Intrinsic::vector_reduce_and:
5113 if (!IsValidAndUminCmp())
5115 AlternativeIID = Intrinsic::vector_reduce_umin;
5117 case Intrinsic::vector_reduce_umin:
5118 if (!IsValidAndUminCmp())
5120 AlternativeIID = Intrinsic::vector_reduce_and;
5133 if (ReductionOpc != Instruction::ICmp)
5144 <<
"\n OrigCost: " << OrigCost
5145 <<
" vs AltCost: " << AltCost <<
"\n");
5147 if (AltCost >= OrigCost)
5151 Type *ScalarTy = VecTy->getScalarType();
5154 Builder.
CreateICmp(Pred, NewReduce, ConstantInt::get(ScalarTy, *CmpVal));
5156 replaceValue(
I, *NewCmp);
5170 unsigned Depth = 0) {
5171 constexpr unsigned MaxLocalDepth = 2;
5172 if (
Depth > MaxLocalDepth)
5175 auto NumSignBits = [&](
const Value *
X) {
5178 if (NumSignBits(V) == V->getType()->getScalarSizeInBits())
5183 return NumSignBits(
A) >= 2 && NumSignBits(
B) >= 2 &&
5194bool VectorCombine::foldReduceAddCmpZero(Instruction &
I) {
5204 if (!VecTy || VecTy->getNumElements() < 2)
5210 if (!IsNonNegative && !IsNonPositive)
5215 unsigned NumElts = VecTy->getNumElements();
5217 if (
Log2_32(NumElts) >= NumSignBits)
5220 ICmpInst::Predicate NewPred;
5222 case ICmpInst::ICMP_EQ:
5223 case ICmpInst::ICMP_ULE:
5224 case ICmpInst::ICMP_SLE:
5225 case ICmpInst::ICMP_SGE:
5226 NewPred = ICmpInst::ICMP_EQ;
5228 case ICmpInst::ICMP_NE:
5229 case ICmpInst::ICMP_UGT:
5230 case ICmpInst::ICMP_SGT:
5231 case ICmpInst::ICMP_SLT:
5232 NewPred = ICmpInst::ICMP_NE;
5242 if (!IsNonNegative &&
5243 (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLE))
5245 if (!IsNonPositive &&
5246 (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGE))
5248 if ((Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLE ||
5249 Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGE) &&
5250 Log2_32(NumElts) >= NumSignBits - 1)
5254 Instruction::Add, VecTy, std::nullopt,
CostKind);
5256 Instruction::Or, VecTy, std::nullopt,
CostKind);
5258 Intrinsic::umax, VecTy, FastMathFlags(),
CostKind);
5261 bool UseOr = OrCost.
isValid() && (!UmaxCost.
isValid() || OrCost <= UmaxCost);
5263 if (AltCost > OrigCost)
5269 Intrinsic::vector_reduce_umax, {VecTy}, {Vec});
5270 Worklist.pushValue(NewReduce);
5272 NewPred, NewReduce, ConstantInt::getNullValue(VecTy->getScalarType()));
5273 replaceValue(
I, *NewCmp);
5282 constexpr unsigned MaxVisited = 32;
5285 bool FoundReduction =
false;
5288 while (!WorkList.
empty()) {
5290 for (
User *U :
I->users()) {
5292 if (!UI || !Visited.
insert(UI).second)
5294 if (Visited.
size() > MaxVisited)
5300 switch (
II->getIntrinsicID()) {
5301 case Intrinsic::vector_reduce_add:
5302 case Intrinsic::vector_reduce_mul:
5303 case Intrinsic::vector_reduce_and:
5304 case Intrinsic::vector_reduce_or:
5305 case Intrinsic::vector_reduce_xor:
5306 case Intrinsic::vector_reduce_smin:
5307 case Intrinsic::vector_reduce_smax:
5308 case Intrinsic::vector_reduce_umin:
5309 case Intrinsic::vector_reduce_umax:
5310 FoundReduction =
true;
5323 return FoundReduction;
5336bool VectorCombine::foldSelectShuffle(Instruction &
I,
bool FromReduction) {
5341 if (!Op0 || !Op1 || Op0 == Op1 || !Op0->isBinaryOp() || !Op1->isBinaryOp() ||
5349 SmallPtrSet<Instruction *, 4> InputShuffles({SVI0A, SVI0B, SVI1A, SVI1B});
5351 if (!
I ||
I->getOperand(0)->getType() != VT)
5353 return any_of(
I->users(), [&](User *U) {
5354 return U != Op0 && U != Op1 &&
5355 !(isa<ShuffleVectorInst>(U) &&
5356 (InputShuffles.contains(cast<Instruction>(U)) ||
5357 isInstructionTriviallyDead(cast<Instruction>(U))));
5360 if (checkSVNonOpUses(SVI0A) || checkSVNonOpUses(SVI0B) ||
5361 checkSVNonOpUses(SVI1A) || checkSVNonOpUses(SVI1B))
5369 for (
auto *U :
I->users()) {
5371 if (!SV || SV->getType() != VT)
5373 if ((SV->getOperand(0) != Op0 && SV->getOperand(0) != Op1) ||
5374 (SV->getOperand(1) != Op0 && SV->getOperand(1) != Op1))
5381 if (!collectShuffles(Op0) || !collectShuffles(Op1))
5385 if (FromReduction && Shuffles.
size() > 1)
5390 if (!FromReduction) {
5391 for (
size_t Idx = 0,
E = Shuffles.
size(); Idx !=
E; ++Idx) {
5392 for (
auto *U : Shuffles[Idx]->
users()) {
5407 int MaxV1Elt = 0, MaxV2Elt = 0;
5408 unsigned NumElts = VT->getNumElements();
5409 for (ShuffleVectorInst *SVN : Shuffles) {
5410 SmallVector<int>
Mask;
5411 SVN->getShuffleMask(Mask);
5415 Value *SVOp0 = SVN->getOperand(0);
5416 Value *SVOp1 = SVN->getOperand(1);
5421 for (
int &Elem : Mask) {
5427 if (SVOp0 == Op1 && SVOp1 == Op0) {
5431 if (SVOp0 != Op0 || SVOp1 != Op1)
5437 SmallVector<int> ReconstructMask;
5438 for (
unsigned I = 0;
I <
Mask.size();
I++) {
5441 }
else if (Mask[
I] <
static_cast<int>(NumElts)) {
5442 MaxV1Elt = std::max(MaxV1Elt, Mask[
I]);
5443 auto It =
find_if(
V1, [&](
const std::pair<int, int> &
A) {
5444 return Mask[
I] ==
A.first;
5450 V1.emplace_back(Mask[
I],
V1.size());
5453 MaxV2Elt = std::max<int>(MaxV2Elt, Mask[
I] - NumElts);
5454 auto It =
find_if(V2, [&](
const std::pair<int, int> &
A) {
5455 return Mask[
I] -
static_cast<int>(NumElts) ==
A.first;
5469 sort(ReconstructMask);
5470 OrigReconstructMasks.
push_back(std::move(ReconstructMask));
5477 if (
V1.empty() || V2.
empty() ||
5478 (MaxV1Elt ==
static_cast<int>(
V1.size()) - 1 &&
5479 MaxV2Elt ==
static_cast<int>(V2.
size()) - 1))
5491 if (InputShuffles.contains(SSV))
5493 return SV->getMaskValue(M);
5501 std::pair<int, int>
Y) {
5502 int MXA = GetBaseMaskValue(
A,
X.first);
5503 int MYA = GetBaseMaskValue(
A,
Y.first);
5507 return SortBase(SVI0A,
A,
B);
5509 stable_sort(V2, [&](std::pair<int, int>
A, std::pair<int, int>
B) {
5510 return SortBase(SVI1A,
A,
B);
5515 for (
const auto &Mask : OrigReconstructMasks) {
5516 SmallVector<int> ReconstructMask;
5517 for (
int M : Mask) {
5519 auto It =
find_if(V, [M](
auto A) {
return A.second ==
M; });
5520 assert(It !=
V.end() &&
"Expected all entries in Mask");
5521 return std::distance(
V.begin(), It);
5525 else if (M <
static_cast<int>(NumElts)) {
5528 ReconstructMask.
push_back(NumElts + FindIndex(V2, M));
5531 ReconstructMasks.
push_back(std::move(ReconstructMask));
5536 SmallVector<int> V1A, V1B, V2A, V2B;
5537 for (
unsigned I = 0;
I <
V1.size();
I++) {
5541 for (
unsigned I = 0;
I < V2.
size();
I++) {
5542 V2A.
push_back(GetBaseMaskValue(SVI1A, V2[
I].first));
5543 V2B.
push_back(GetBaseMaskValue(SVI1B, V2[
I].first));
5545 while (V1A.
size() < NumElts) {
5549 while (V2A.
size() < NumElts) {
5561 VT, VT, SV->getShuffleMask(),
CostKind);
5568 unsigned ElementSize = VT->getElementType()->getPrimitiveSizeInBits();
5569 unsigned MaxVectorSize =
5571 unsigned MaxElementsInVector = MaxVectorSize / ElementSize;
5572 if (MaxElementsInVector == 0)
5581 std::set<SmallVector<int, 4>> UniqueShuffles;
5586 unsigned NumFullVectors =
Mask.size() / MaxElementsInVector;
5587 if (NumFullVectors < 2)
5588 return C + ShuffleCost;
5589 SmallVector<int, 4> SubShuffle(MaxElementsInVector);
5590 unsigned NumUniqueGroups = 0;
5591 unsigned NumGroups =
Mask.size() / MaxElementsInVector;
5594 for (
unsigned I = 0;
I < NumFullVectors; ++
I) {
5595 for (
unsigned J = 0; J < MaxElementsInVector; ++J)
5596 SubShuffle[J] = Mask[MaxElementsInVector *
I + J];
5597 if (UniqueShuffles.insert(SubShuffle).second)
5598 NumUniqueGroups += 1;
5600 return C + ShuffleCost * NumUniqueGroups / NumGroups;
5606 SmallVector<int, 16>
Mask;
5607 SV->getShuffleMask(Mask);
5608 return AddShuffleMaskAdjustedCost(
C, Mask);
5611 auto AllShufflesHaveSameOperands =
5612 [](SmallPtrSetImpl<Instruction *> &InputShuffles) {
5613 if (InputShuffles.size() < 2)
5615 ShuffleVectorInst *FirstSV =
5622 std::next(InputShuffles.begin()), InputShuffles.end(),
5623 [&](Instruction *
I) {
5624 ShuffleVectorInst *SV = dyn_cast<ShuffleVectorInst>(I);
5625 return SV && SV->getOperand(0) == In0 && SV->getOperand(1) == In1;
5634 CostBefore += std::accumulate(Shuffles.begin(), Shuffles.end(),
5636 if (AllShufflesHaveSameOperands(InputShuffles)) {
5637 UniqueShuffles.clear();
5638 CostBefore += std::accumulate(InputShuffles.begin(), InputShuffles.end(),
5641 CostBefore += std::accumulate(InputShuffles.begin(), InputShuffles.end(),
5647 FixedVectorType *Op0SmallVT =
5649 FixedVectorType *Op1SmallVT =
5654 UniqueShuffles.clear();
5655 CostAfter += std::accumulate(ReconstructMasks.begin(), ReconstructMasks.end(),
5657 std::set<SmallVector<int>> OutputShuffleMasks({V1A, V1B, V2A, V2B});
5659 std::accumulate(OutputShuffleMasks.begin(), OutputShuffleMasks.end(),
5662 LLVM_DEBUG(
dbgs() <<
"Found a binop select shuffle pattern: " <<
I <<
"\n");
5664 <<
" vs CostAfter: " << CostAfter <<
"\n");
5665 if (CostBefore < CostAfter ||
5676 if (InputShuffles.contains(SSV))
5678 return SV->getOperand(
Op);
5682 GetShuffleOperand(SVI0A, 1), V1A);
5685 GetShuffleOperand(SVI0B, 1), V1B);
5688 GetShuffleOperand(SVI1A, 1), V2A);
5691 GetShuffleOperand(SVI1B, 1), V2B);
5696 I->copyIRFlags(Op0,
true);
5701 I->copyIRFlags(Op1,
true);
5703 for (
int S = 0,
E = ReconstructMasks.size(); S !=
E; S++) {
5706 replaceValue(*Shuffles[S], *NSV,
false);
5709 Worklist.pushValue(NSV0A);
5710 Worklist.pushValue(NSV0B);
5711 Worklist.pushValue(NSV1A);
5712 Worklist.pushValue(NSV1B);
5722bool VectorCombine::shrinkType(Instruction &
I) {
5723 Value *ZExted, *OtherOperand;
5729 Value *ZExtOperand =
I.getOperand(
I.getOperand(0) == OtherOperand ? 1 : 0);
5733 unsigned BW = SmallTy->getElementType()->getPrimitiveSizeInBits();
5735 if (
I.getOpcode() == Instruction::LShr) {
5752 Instruction::ZExt, BigTy, SmallTy,
5753 TargetTransformInfo::CastContextHint::None,
CostKind);
5758 for (User *U : ZExtOperand->
users()) {
5765 ShrinkCost += ZExtCost;
5780 ShrinkCost += ZExtCost;
5787 Instruction::Trunc, SmallTy, BigTy,
5788 TargetTransformInfo::CastContextHint::None,
CostKind);
5793 if (ShrinkCost > CurrentCost)
5797 Value *Op0 = ZExted;
5800 if (
I.getOperand(0) == OtherOperand)
5807 replaceValue(
I, *NewZExtr);
5813bool VectorCombine::foldInsExtVectorToShuffle(Instruction &
I) {
5814 Value *DstVec, *SrcVec;
5815 uint64_t ExtIdx, InsIdx;
5825 if (!DstVecTy || !SrcVecTy ||
5831 if (InsIdx >= NumDstElts || ExtIdx >= NumSrcElts || NumDstElts == 1)
5838 bool NeedExpOrNarrow = NumSrcElts != NumDstElts;
5840 if (NeedDstSrcSwap) {
5842 Mask[InsIdx] = ExtIdx % NumDstElts;
5846 std::iota(
Mask.begin(),
Mask.end(), 0);
5847 Mask[InsIdx] = (ExtIdx % NumDstElts) + NumDstElts;
5860 SmallVector<int> ExtToVecMask;
5861 if (!NeedExpOrNarrow) {
5866 nullptr, {DstVec, SrcVec});
5872 ExtToVecMask[ExtIdx % NumDstElts] = ExtIdx;
5875 DstVecTy, SrcVecTy, ExtToVecMask,
CostKind);
5879 if (!Ext->hasOneUse())
5882 LLVM_DEBUG(
dbgs() <<
"Found a insert/extract shuffle-like pair: " <<
I
5883 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
5886 if (OldCost < NewCost)
5889 if (NeedExpOrNarrow) {
5890 if (!NeedDstSrcSwap)
5903 replaceValue(
I, *Shuf);
5912bool VectorCombine::foldInterleaveIntrinsics(Instruction &
I) {
5913 const APInt *SplatVal0, *SplatVal1;
5923 auto *ExtVTy = VectorType::getExtendedElementVectorType(VTy);
5924 unsigned Width = VTy->getElementType()->getIntegerBitWidth();
5933 LLVM_DEBUG(
dbgs() <<
"VC: The cost to cast from " << *ExtVTy <<
" to "
5934 << *
I.getType() <<
" is too high.\n");
5938 APInt NewSplatVal = SplatVal1->
zext(Width * 2);
5939 NewSplatVal <<= Width;
5940 NewSplatVal |= SplatVal0->
zext(Width * 2);
5942 ExtVTy->getElementCount(), ConstantInt::get(
F.getContext(), NewSplatVal));
5977bool VectorCombine::foldDeinterleaveIntrinsics(Instruction &
I) {
5979 if (
DL->isBigEndian())
5982 using namespace PatternMatch;
5983 Value *DeinterleavedVal;
5994 unsigned HalfElementWidth = ElementWidth / 2;
5998 std::array<ExtractValueInst *, 2> OrigFields{};
5999 for (User *Usr :
I.users()) {
6002 if (!
E ||
E->getNumIndices() != 1)
6004 unsigned Idx = *
E->idx_begin();
6006 if (Idx >= 2 || OrigFields[Idx] || !
E->hasNUses(2))
6008 OrigFields[Idx] =
E;
6012 SmallVector<Instruction *, 2> MergeInsts;
6013 for (
auto *FieldUsr : OrigFields[0]->
users()) {
6021 auto MatchMerge = [&](void) ->
bool {
6024 return match(MergeInsts[0],
6028 match(MergeInsts[1],
6033 if (!MatchMerge()) {
6034 std::swap(MergeInsts[0], MergeInsts[1]);
6049 auto *NewFieldTy = VecTy->getWithNewBitWidth(HalfElementWidth);
6059 if (OldCost <= NewCost || !NewCost.
isValid()) {
6061 dbgs() <<
"VC: New deinterleave2 sequence cost (" << NewCost <<
")"
6062 <<
" is higher than that of the old one (" << OldCost <<
")\n");
6070 Intrinsic::vector_deinterleave2, {NewVecTy}, {NewVecCast});
6071 for (
auto [Idx, MergeInst] :
enumerate(MergeInsts)) {
6073 NewField = Builder.
CreateBitCast(NewField, MergeInst->getType());
6074 replaceValue(*MergeInst, *NewField);
6080bool VectorCombine::foldBitcastOfVPLoad(Instruction &
I) {
6081 const DataLayout &
DL =
I.getDataLayout();
6096 DL.getValueOrABITypeAlignment(
II->getPointerAlignment(), OrigVecTy);
6097 ElementCount OrigVecCnt = OrigVecTy->getElementCount();
6099 ElementCount NewVecCnt = NewVecTy->getElementCount();
6111 II->getMemoryPointerParam(),
false,
6117 {Intrinsic::vp_load, NewVecTy,
II->getMemoryPointerParam(),
false,
6121 <<
" NewCost=" << NewCost <<
"\n");
6122 if (NewCost > OldCost || !NewCost.
isValid())
6129 NewVecTy, Intrinsic::vp_load,
6130 {
II->getMemoryPointerParam(), NewMask, NewEVL});
6133 0, AttrBuilder(
II->getContext()).addAlignmentAttr(OrigAlign));
6134 replaceValue(*Cast, *NewVP);
6144bool VectorCombine::foldBitOrderReverseAndSwap(Instruction &
I) {
6148 Type *Ty =
X->getType();
6149 Type *VecTy =
I.getOperand(0)->getType();
6163 if (CanUseBswap || CanUseFshl) {
6174 IntrinsicCostAttributes ICABSwap(Intrinsic::bswap, Ty, {Ty});
6175 IntrinsicCostAttributes ICABFshl(Intrinsic::fshl, Ty, {
X,
X, HalfBW},
6177 IntrinsicCostAttributes ICABRev(Intrinsic::bitreverse, Ty, {Ty});
6182 if (!InnerCall->hasOneUse())
6185 else if (!InnerBitCast->hasOneUse())
6188 <<
"\n OldCost: " << OldCost
6189 <<
" vs NewCost: " << NewCost <<
"\n");
6190 if (NewCost.isValid() && NewCost < OldCost) {
6196 Worklist.pushValue(Swap);
6198 replaceValue(
I, *BRev);
6207 Type *Ty =
I.getType();
6209 TypeSize ElementSize =
DL->getTypeStoreSize(Ty);
6212 Type *NewVecTy = VectorType::get(I8Ty, NewVecCnt);
6225 IntrinsicCostAttributes ICANew(Intrinsic::bitreverse, NewVecTy, {NewVecTy});
6228 InstructionCost NewCost = CastToVecCost + NewIntrinsicCost + CastToOrigCost;
6229 if (!InnerII->hasOneUse())
6232 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
6234 if (!NewCost.
isValid() || NewCost >= OldCost)
6242 replaceValue(
I, *CastToOrig);
6252 unsigned RawNumElements = MaxIdx + 1u;
6255 if (!
TTI.isTypeLegal(ElemTy))
6256 return RawNumElements;
6258 TypeSize ElemSize =
DL.getTypeSizeInBits(ElemTy);
6260 return RawNumElements;
6265 return RawNumElements;
6270 if (ElemsPerReg == 0 || RawNumElements <= ElemsPerReg)
6271 return RawNumElements;
6273 return alignTo(RawNumElements, ElemsPerReg);
6277bool VectorCombine::shrinkLoadForShuffles(Instruction &
I) {
6279 if (!OldLoad || !OldLoad->isSimple())
6286 unsigned const OldNumElements = OldLoadTy->getNumElements();
6292 using IndexRange = std::pair<int, int>;
6293 auto GetIndexRangeInShuffles = [&]() -> std::optional<IndexRange> {
6294 IndexRange OutputRange = IndexRange(OldNumElements, -1);
6295 for (llvm::Use &Use :
I.uses()) {
6297 User *Shuffle =
Use.getUser();
6302 return std::nullopt;
6309 for (
int Index : Mask) {
6310 if (Index >= 0 && Index <
static_cast<int>(OldNumElements)) {
6311 OutputRange.first = std::min(Index, OutputRange.first);
6312 OutputRange.second = std::max(Index, OutputRange.second);
6317 if (OutputRange.second < OutputRange.first)
6318 return std::nullopt;
6324 if (std::optional<IndexRange> Indices = GetIndexRangeInShuffles()) {
6325 unsigned const NewNumElements =
6330 if (NewNumElements < OldNumElements) {
6335 Type *ElemTy = OldLoadTy->getElementType();
6337 Value *PtrOp = OldLoad->getPointerOperand();
6340 Instruction::Load, OldLoad->getType(), OldLoad->getAlign(),
6341 OldLoad->getPointerAddressSpace(),
CostKind);
6344 OldLoad->getPointerAddressSpace(),
CostKind);
6346 using UseEntry = std::pair<ShuffleVectorInst *, std::vector<int>>;
6348 unsigned const MaxIndex = NewNumElements * 2u;
6350 for (llvm::Use &Use :
I.uses()) {
6357 ArrayRef<int> OldMask = Shuffle->getShuffleMask();
6363 for (
int Index : OldMask) {
6364 if (Index >=
static_cast<int>(MaxIndex))
6378 dbgs() <<
"Found a load used only by shufflevector instructions: "
6379 <<
I <<
"\n OldCost: " << OldCost
6380 <<
" vs NewCost: " << NewCost <<
"\n");
6382 if (OldCost < NewCost || !NewCost.
isValid())
6388 NewLoad->copyMetadata(
I);
6391 for (UseEntry &Use : NewUses) {
6392 ShuffleVectorInst *Shuffle =
Use.first;
6393 std::vector<int> &NewMask =
Use.second;
6400 replaceValue(*Shuffle, *NewShuffle,
false);
6413bool VectorCombine::shrinkPhiOfShuffles(Instruction &
I) {
6415 if (!Phi ||
Phi->getNumIncomingValues() != 2u)
6419 ArrayRef<int> Mask0;
6420 ArrayRef<int> Mask1;
6433 auto const InputNumElements = InputVT->getNumElements();
6435 if (InputNumElements >= ResultVT->getNumElements())
6440 SmallVector<int, 16> NewMask;
6443 for (
auto [
M0,
M1] :
zip(Mask0, Mask1)) {
6444 if (
M0 >= 0 &&
M1 >= 0)
6446 else if (
M0 == -1 &&
M1 == -1)
6459 int MaskOffset = NewMask[0
u];
6460 unsigned Index = (InputNumElements + MaskOffset) % InputNumElements;
6463 for (
unsigned I = 0u;
I < InputNumElements; ++
I) {
6477 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
6480 if (NewCost > OldCost)
6492 auto *NewPhi = Builder.
CreatePHI(NewShuf0->getType(), 2u);
6494 NewPhi->addIncoming(
Op,
Phi->getIncomingBlock(1u));
6500 replaceValue(*Phi, *NewShuf1);
6506bool VectorCombine::run() {
6520 auto Opcode =
I.getOpcode();
6528 if (IsFixedVectorType) {
6530 case Instruction::InsertElement:
6531 if (vectorizeLoadInsert(
I))
6534 case Instruction::ShuffleVector:
6535 if (widenSubvectorLoad(
I))
6546 if (scalarizeOpOrCmp(
I))
6548 if (scalarizeLoad(
I))
6550 if (scalarizeExtExtract(
I))
6552 if (scalarizeVPIntrinsic(
I))
6554 if (foldInterleaveIntrinsics(
I))
6556 if (foldBitcastOfVPLoad(
I))
6560 if (foldDeinterleaveIntrinsics(
I))
6563 if (Opcode == Instruction::Store)
6564 if (foldSingleElementStore(
I))
6568 if (TryEarlyFoldsOnly)
6571 if (Opcode == Instruction::Call)
6572 if (foldBitOrderReverseAndSwap(
I))
6574 if (Opcode == Instruction::BitCast)
6575 if (foldBitOrderReverseAndSwap(
I))
6582 if (IsFixedVectorType) {
6584 case Instruction::InsertElement:
6585 if (foldInsExtFNeg(
I))
6587 if (foldInsExtBinop(
I))
6589 if (foldInsExtVectorToShuffle(
I))
6592 case Instruction::ShuffleVector:
6593 if (foldPermuteOfBinops(
I))
6595 if (foldShuffleOfBinops(
I))
6597 if (foldShuffleOfSelects(
I))
6599 if (foldShuffleOfCastops(
I))
6601 if (foldShuffleOfShuffles(
I))
6603 if (foldPermuteOfIntrinsic(
I))
6605 if (foldShufflesOfLengthChangingShuffles(
I))
6607 if (foldShuffleOfIntrinsics(
I))
6609 if (foldSelectShuffle(
I))
6611 if (foldShuffleToIdentity(
I))
6614 case Instruction::Load:
6615 if (shrinkLoadForShuffles(
I))
6618 case Instruction::BitCast:
6619 if (foldBitcastShuffle(
I))
6621 if (foldSelectsFromBitcast(
I))
6624 case Instruction::And:
6625 case Instruction::Or:
6626 case Instruction::Xor:
6627 if (foldBitOpOfCastops(
I))
6629 if (foldBitOpOfCastConstant(
I))
6632 case Instruction::PHI:
6633 if (shrinkPhiOfShuffles(
I))
6643 case Instruction::Call:
6644 if (foldShuffleFromReductions(
I))
6646 if (foldCastFromReductions(
I))
6649 case Instruction::ExtractElement:
6650 if (foldShuffleChainsToReduce(
I))
6653 case Instruction::ICmp:
6654 if (foldSignBitReductionCmp(
I))
6656 if (foldICmpEqZeroVectorReduce(
I))
6658 if (foldReductionZeroTest(
I))
6660 if (foldEquivalentReductionCmp(
I))
6662 if (foldReduceAddCmpZero(
I))
6665 case Instruction::FCmp:
6666 if (foldExtractExtract(
I))
6669 case Instruction::Or:
6670 if (foldConcatOfBoolMasks(
I))
6675 if (foldExtractExtract(
I))
6677 if (foldExtractedCmps(
I))
6679 if (foldBinopOfReductions(
I))
6688 bool MadeChange =
false;
6689 for (BasicBlock &BB :
F) {
6701 if (!
I->isDebugOrPseudoInst())
6702 MadeChange |= FoldInst(*
I);
6709 while (!Worklist.isEmpty()) {
6719 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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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)
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
const SmallVectorImpl< MachineOperand > & Cond
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
This file defines the scope_exit class, which executes user-defined cleanup logic at scope exit.
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 isEquivBitcast(Value *X, Value *Y)
Helper to peek through bitcasts to the same value.
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 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, InstructionWorklist &WorkList, const TargetTransformInfo *TTI)
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 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 unsigned getAlignedNumElements(unsigned MaxIdx, FixedVectorType *LoadTy, const TargetTransformInfo &TTI, const DataLayout &DL)
Given the maximum shuffle index and load vector type, compute the number of elements for the shrunk l...
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.
uint64_t getZExtValue() const
Get zero extended value.
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
Class to represent fixed width SIMD vectors.
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...
InstructionWorklist - This is the worklist management logic for InstCombine and other simplification ...
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.
LLVM_ABI unsigned getIntegerBitWidth() const
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 const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
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.
constexpr bool isZero() const
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.
@ 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.
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
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 >
@ Load
The value being inserted comes from a load (InsertElement only).
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.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
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