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);
227 Load->getFunction()->hasFnAttribute(Attribute::SanitizeMemTag) ||
233 Type *ScalarTy =
Load->getType()->getScalarType();
235 unsigned MinVectorSize =
TTI.getMinVectorRegisterBitWidth();
236 if (!ScalarSize || !MinVectorSize || MinVectorSize % ScalarSize != 0 ||
243bool VectorCombine::vectorizeLoadInsert(
Instruction &
I) {
269 Value *SrcPtr =
Load->getPointerOperand()->stripPointerCasts();
272 unsigned MinVecNumElts = MinVectorSize / ScalarSize;
273 auto *MinVecTy = VectorType::get(ScalarTy, MinVecNumElts,
false);
274 unsigned OffsetEltIndex = 0;
282 unsigned OffsetBitWidth =
DL->getIndexTypeSizeInBits(SrcPtr->
getType());
283 APInt
Offset(OffsetBitWidth, 0);
293 uint64_t ScalarSizeInBytes = ScalarSize / 8;
294 if (
Offset.urem(ScalarSizeInBytes) != 0)
298 APInt OffsetEltIndexAP =
Offset.udiv(ScalarSizeInBytes);
299 if (OffsetEltIndexAP.
uge(MinVecNumElts))
317 unsigned AS =
Load->getPointerAddressSpace();
336 unsigned OutputNumElts = Ty->getNumElements();
338 assert(OffsetEltIndex < MinVecNumElts &&
"Address offset too big");
339 Mask[0] = OffsetEltIndex;
346 if (OldCost < NewCost || !NewCost.
isValid())
357 replaceValue(
I, *VecLd);
365bool VectorCombine::widenSubvectorLoad(Instruction &
I) {
368 if (!Shuf->isIdentityWithPadding())
374 unsigned OpIndex =
any_of(Shuf->getShuffleMask(), [&NumOpElts](
int M) {
375 return M >= (int)(NumOpElts);
395 unsigned AS =
Load->getPointerAddressSpace();
410 if (OldCost < NewCost || !NewCost.
isValid())
417 replaceValue(
I, *VecLd);
424ExtractElementInst *VectorCombine::getShuffleExtract(
425 ExtractElementInst *Ext0, ExtractElementInst *Ext1,
429 assert(Index0C && Index1C &&
"Expected constant extract indexes");
431 unsigned Index0 = Index0C->getZExtValue();
432 unsigned Index1 = Index1C->getZExtValue();
435 if (Index0 == Index1)
459 if (PreferredExtractIndex == Index0)
461 if (PreferredExtractIndex == Index1)
465 return Index0 > Index1 ? Ext0 : Ext1;
473bool VectorCombine::isExtractExtractCheap(ExtractElementInst *Ext0,
474 ExtractElementInst *Ext1,
475 const Instruction &
I,
476 ExtractElementInst *&ConvertToShuffle,
477 unsigned PreferredExtractIndex) {
480 assert(Ext0IndexC && Ext1IndexC &&
"Expected constant extract indexes");
482 unsigned Opcode =
I.getOpcode();
495 assert((Opcode == Instruction::ICmp || Opcode == Instruction::FCmp) &&
496 "Expected a compare");
506 unsigned Ext0Index = Ext0IndexC->getZExtValue();
507 unsigned Ext1Index = Ext1IndexC->getZExtValue();
521 unsigned BestExtIndex = Extract0Cost > Extract1Cost ? Ext0Index : Ext1Index;
522 unsigned BestInsIndex = Extract0Cost > Extract1Cost ? Ext1Index : Ext0Index;
523 InstructionCost CheapExtractCost = std::min(Extract0Cost, Extract1Cost);
528 if (Ext0Src == Ext1Src && Ext0Index == Ext1Index) {
533 bool HasUseTax = Ext0 == Ext1 ? !Ext0->
hasNUses(2)
535 OldCost = CheapExtractCost + ScalarOpCost;
536 NewCost = VectorOpCost + CheapExtractCost + HasUseTax * CheapExtractCost;
540 OldCost = Extract0Cost + Extract1Cost + ScalarOpCost;
541 NewCost = VectorOpCost + CheapExtractCost +
546 ConvertToShuffle = getShuffleExtract(Ext0, Ext1, PreferredExtractIndex);
547 if (ConvertToShuffle) {
559 SmallVector<int> ShuffleMask(FixedVecTy->getNumElements(),
561 ShuffleMask[BestInsIndex] = BestExtIndex;
563 VecTy, VecTy, ShuffleMask,
CostKind, 0,
564 nullptr, {ConvertToShuffle});
567 VecTy, VecTy, {},
CostKind, 0,
nullptr,
572 LLVM_DEBUG(
dbgs() <<
"Found a binop of extractions: " <<
I <<
"\n OldCost: "
573 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
578 return OldCost < NewCost;
590 ShufMask[NewIndex] = OldIndex;
591 return Builder.CreateShuffleVector(Vec, ShufMask,
"shift");
643 V1,
"foldExtExtBinop");
648 VecBOInst->copyIRFlags(&
I);
654bool VectorCombine::foldExtractExtract(Instruction &
I) {
675 unsigned NumElts = FixedVecTy->getNumElements();
676 if (C0 >= NumElts || C1 >= NumElts)
692 ExtractElementInst *ExtractToChange;
693 if (isExtractExtractCheap(Ext0, Ext1,
I, ExtractToChange, InsertIndex))
699 if (ExtractToChange) {
700 unsigned CheapExtractIdx = ExtractToChange == Ext0 ? C1 : C0;
705 if (ExtractToChange == Ext0)
714 ? foldExtExtCmp(ExtOp0, ExtOp1, ExtIndex,
I)
715 : foldExtExtBinop(ExtOp0, ExtOp1, ExtIndex,
I);
718 replaceValue(
I, *NewExt);
724bool VectorCombine::foldInsExtFNeg(Instruction &
I) {
727 uint64_t ExtIdx, InsIdx;
742 auto *DstVecScalarTy = DstVecTy->getScalarType();
744 if (!SrcVecTy || DstVecScalarTy != SrcVecTy->getScalarType())
749 unsigned NumDstElts = DstVecTy->getNumElements();
750 unsigned NumSrcElts = SrcVecTy->getNumElements();
751 if (ExtIdx > NumSrcElts || InsIdx >= NumDstElts || NumDstElts == 1)
757 SmallVector<int>
Mask(NumDstElts);
758 std::iota(
Mask.begin(),
Mask.end(), 0);
759 Mask[InsIdx] = (ExtIdx % NumDstElts) + NumDstElts;
775 bool NeedLenChg = SrcVecTy->getNumElements() != NumDstElts;
778 SmallVector<int> SrcMask;
781 SrcMask[ExtIdx % NumDstElts] = ExtIdx;
783 DstVecTy, SrcVecTy, SrcMask,
CostKind);
787 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
789 if (NewCost > OldCost)
792 Value *NewShuf, *LenChgShuf =
nullptr;
806 replaceValue(
I, *NewShuf);
812bool VectorCombine::foldInsExtBinop(Instruction &
I) {
813 BinaryOperator *VecBinOp, *SclBinOp;
845 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
847 if (NewCost > OldCost)
858 NewInst->copyIRFlags(VecBinOp);
859 NewInst->andIRFlags(SclBinOp);
864 replaceValue(
I, *NewBO);
870bool VectorCombine::foldBitOpOfCastops(Instruction &
I) {
873 if (!BinOp || !BinOp->isBitwiseLogicOp())
879 if (!LHSCast || !RHSCast) {
880 LLVM_DEBUG(
dbgs() <<
" One or both operands are not cast instructions\n");
886 if (CastOpcode != RHSCast->getOpcode())
890 switch (CastOpcode) {
891 case Instruction::BitCast:
892 case Instruction::Trunc:
893 case Instruction::SExt:
894 case Instruction::ZExt:
900 Value *LHSSrc = LHSCast->getOperand(0);
901 Value *RHSSrc = RHSCast->getOperand(0);
907 auto *SrcTy = LHSSrc->
getType();
908 auto *DstTy =
I.getType();
911 if (CastOpcode != Instruction::BitCast &&
916 if (!SrcTy->getScalarType()->isIntegerTy() ||
917 !DstTy->getScalarType()->isIntegerTy())
932 LHSCastCost + RHSCastCost;
943 if (!LHSCast->hasOneUse())
944 NewCost += LHSCastCost;
945 if (!RHSCast->hasOneUse())
946 NewCost += RHSCastCost;
949 <<
" NewCost=" << NewCost <<
"\n");
951 if (NewCost > OldCost)
956 BinOp->getName() +
".inner");
958 NewBinOp->copyIRFlags(BinOp);
972 replaceValue(
I, *Result);
981bool VectorCombine::foldBitOpOfCastConstant(Instruction &
I) {
997 switch (CastOpcode) {
998 case Instruction::BitCast:
999 case Instruction::ZExt:
1000 case Instruction::SExt:
1001 case Instruction::Trunc:
1007 Value *LHSSrc = LHSCast->getOperand(0);
1009 auto *SrcTy = LHSSrc->
getType();
1010 auto *DstTy =
I.getType();
1013 if (CastOpcode != Instruction::BitCast &&
1018 if (!SrcTy->getScalarType()->isIntegerTy() ||
1019 !DstTy->getScalarType()->isIntegerTy())
1023 PreservedCastFlags RHSFlags;
1048 if (!LHSCast->hasOneUse())
1049 NewCost += LHSCastCost;
1051 LLVM_DEBUG(
dbgs() <<
"foldBitOpOfCastConstant: OldCost=" << OldCost
1052 <<
" NewCost=" << NewCost <<
"\n");
1054 if (NewCost > OldCost)
1059 LHSSrc, InvC,
I.getName() +
".inner");
1061 NewBinOp->copyIRFlags(&
I);
1081 replaceValue(
I, *Result);
1088bool VectorCombine::foldBitcastShuffle(Instruction &
I) {
1102 if (!DestTy || !SrcTy)
1105 unsigned DestEltSize = DestTy->getScalarSizeInBits();
1106 unsigned SrcEltSize = SrcTy->getScalarSizeInBits();
1107 if (SrcTy->getPrimitiveSizeInBits() % DestEltSize != 0)
1117 if (!(BCTy0 && BCTy0->getElementType() == DestTy->getElementType()) &&
1118 !(BCTy1 && BCTy1->getElementType() == DestTy->getElementType()))
1122 SmallVector<int, 16> NewMask;
1123 if (DestEltSize <= SrcEltSize) {
1126 if (SrcEltSize % DestEltSize != 0)
1128 unsigned ScaleFactor = SrcEltSize / DestEltSize;
1133 if (DestEltSize % SrcEltSize != 0)
1135 unsigned ScaleFactor = DestEltSize / SrcEltSize;
1142 unsigned NumSrcElts = SrcTy->getPrimitiveSizeInBits() / DestEltSize;
1143 auto *NewShuffleTy =
1145 auto *OldShuffleTy =
1147 unsigned NumOps = IsUnary ? 1 : 2;
1157 TargetTransformInfo::CastContextHint::None,
1162 TargetTransformInfo::CastContextHint::None,
1165 LLVM_DEBUG(
dbgs() <<
"Found a bitcasted shuffle: " <<
I <<
"\n OldCost: "
1166 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
1168 if (NewCost > OldCost || !NewCost.
isValid())
1176 replaceValue(
I, *Shuf);
1183bool VectorCombine::scalarizeVPIntrinsic(Instruction &
I) {
1197 if (!ScalarOp0 || !ScalarOp1)
1205 auto IsAllTrueMask = [](
Value *MaskVal) {
1208 return ConstValue->isAllOnesValue();
1222 SmallVector<int>
Mask;
1224 Mask.resize(FVTy->getNumElements(), 0);
1233 Args.push_back(
V->getType());
1234 IntrinsicCostAttributes
Attrs(IntrID, VecTy, Args);
1239 std::optional<unsigned> FunctionalOpcode =
1241 std::optional<Intrinsic::ID> ScalarIntrID = std::nullopt;
1242 if (!FunctionalOpcode) {
1251 IntrinsicCostAttributes
Attrs(*ScalarIntrID, VecTy->getScalarType(), Args);
1261 InstructionCost NewCost = ScalarOpCost + SplatCost + CostToKeepSplats;
1263 LLVM_DEBUG(
dbgs() <<
"Found a VP Intrinsic to scalarize: " << VPI
1266 <<
", Cost of scalarizing:" << NewCost <<
"\n");
1269 if (OldCost < NewCost || !NewCost.
isValid())
1280 bool SafeToSpeculate;
1286 *FunctionalOpcode, &VPI,
nullptr, SQ.
AC, SQ.
DT);
1287 if (!SafeToSpeculate &&
1294 {ScalarOp0, ScalarOp1})
1296 ScalarOp0, ScalarOp1);
1305bool VectorCombine::scalarizeOpOrCmp(Instruction &
I) {
1310 if (!UO && !BO && !CI && !
II)
1318 if (Arg->getType() !=
II->getType() &&
1328 for (User *U :
I.users())
1335 std::optional<uint64_t>
Index;
1337 auto Ops =
II ?
II->args() :
I.operands();
1341 uint64_t InsIdx = 0;
1346 if (OpTy->getElementCount().getKnownMinValue() <= InsIdx)
1352 else if (InsIdx != *Index)
1369 if (!
Index.has_value())
1373 Type *ScalarTy = VecTy->getScalarType();
1374 assert(VecTy->isVectorTy() &&
1377 "Unexpected types for insert element into binop or cmp");
1379 unsigned Opcode =
I.getOpcode();
1387 }
else if (UO || BO) {
1391 IntrinsicCostAttributes ScalarICA(
1392 II->getIntrinsicID(), ScalarTy,
1395 IntrinsicCostAttributes VectorICA(
1396 II->getIntrinsicID(), VecTy,
1403 Value *NewVecC =
nullptr;
1405 NewVecC =
simplifyCmpInst(CI->getPredicate(), VecCs[0], VecCs[1], SQ);
1408 simplifyUnOp(UO->getOpcode(), VecCs[0], UO->getFastMathFlags(), SQ);
1410 NewVecC =
simplifyBinOp(BO->getOpcode(), VecCs[0], VecCs[1], SQ);
1424 for (
auto [Idx,
Op, VecC, Scalar] :
enumerate(
Ops, VecCs, ScalarOps)) {
1426 II->getIntrinsicID(), Idx, &
TTI)))
1429 Instruction::InsertElement, VecTy,
CostKind, *Index, VecC, Scalar);
1430 OldCost += InsertCost;
1431 NewCost += !
Op->hasOneUse() * InsertCost;
1435 if (OldCost < NewCost || !NewCost.
isValid())
1445 ++NumScalarIntrinsic;
1455 Scalar = Builder.
CreateCmp(CI->getPredicate(), ScalarOps[0], ScalarOps[1]);
1461 Scalar->setName(
I.getName() +
".scalar");
1466 ScalarInst->copyIRFlags(&
I);
1469 replaceValue(
I, *Insert);
1476bool VectorCombine::foldExtractedCmps(Instruction &
I) {
1481 if (!BI || !
I.getType()->isIntegerTy(1))
1486 Value *B0 =
I.getOperand(0), *B1 =
I.getOperand(1);
1489 CmpPredicate
P0,
P1;
1501 uint64_t Index0, Index1;
1508 ExtractElementInst *ConvertToShuf = getShuffleExtract(Ext0, Ext1,
CostKind);
1511 assert((ConvertToShuf == Ext0 || ConvertToShuf == Ext1) &&
1512 "Unknown ExtractElementInst");
1517 unsigned CmpOpcode =
1523 if (Index0 >= VecTy->getNumElements() || Index1 >= VecTy->getNumElements())
1535 Ext0Cost + Ext1Cost + CmpCost * 2 +
1541 int CheapIndex = ConvertToShuf == Ext0 ? Index1 : Index0;
1542 int ExpensiveIndex = ConvertToShuf == Ext0 ? Index0 : Index1;
1547 ShufMask[CheapIndex] = ExpensiveIndex;
1552 NewCost += Ext0->
hasOneUse() ? 0 : Ext0Cost;
1553 NewCost += Ext1->
hasOneUse() ? 0 : Ext1Cost;
1558 if (OldCost < NewCost || !NewCost.
isValid())
1568 Value *
LHS = ConvertToShuf == Ext0 ? Shuf : VCmp;
1569 Value *
RHS = ConvertToShuf == Ext0 ? VCmp : Shuf;
1572 replaceValue(
I, *NewExt);
1599bool VectorCombine::foldSelectsFromBitcast(Instruction &
I) {
1606 if (!SrcVecTy || !DstVecTy)
1616 if (SrcEltBits != 32 && SrcEltBits != 64)
1619 if (!DstEltTy->
isIntegerTy() || DstEltBits >= SrcEltBits)
1636 if (!ScalarSelCost.
isValid() || ScalarSelCost == 0)
1639 unsigned MinSelects = (VecSelCost.
getValue() / ScalarSelCost.
getValue()) + 1;
1642 if (!BC->hasNUsesOrMore(MinSelects))
1647 DenseMap<Value *, SmallVector<SelectInst *, 8>> CondToSelects;
1649 for (User *U : BC->users()) {
1654 for (User *ExtUser : Ext->users()) {
1658 Cond->getType()->isIntegerTy(1))
1663 if (CondToSelects.
empty())
1666 bool MadeChange =
false;
1667 Value *SrcVec = BC->getOperand(0);
1670 for (
auto [
Cond, Selects] : CondToSelects) {
1672 if (Selects.size() < MinSelects) {
1673 LLVM_DEBUG(
dbgs() <<
"VectorCombine: foldSelectsFromBitcast not "
1674 <<
"profitable (VecCost=" << VecSelCost
1675 <<
", ScalarCost=" << ScalarSelCost
1676 <<
", NumSelects=" << Selects.size() <<
")\n");
1681 auto InsertPt = std::next(BC->getIterator());
1685 InsertPt = std::next(CondInst->getIterator());
1693 for (SelectInst *Sel : Selects) {
1695 Value *Idx = Ext->getIndexOperand();
1699 replaceValue(*Sel, *NewExt);
1704 <<
" selects into vector select\n");
1718 unsigned ReductionOpc =
1724 CostBeforeReduction =
1725 TTI.getCastInstrCost(RedOp->getOpcode(), VecRedTy, ExtType,
1727 CostAfterReduction =
1728 TTI.getExtendedReductionCost(ReductionOpc, IsUnsigned,
II.getType(),
1732 if (RedOp &&
II.getIntrinsicID() == Intrinsic::vector_reduce_add &&
1738 (Op0->
getOpcode() == RedOp->getOpcode() || Op0 == Op1)) {
1745 TTI.getCastInstrCost(Op0->
getOpcode(), MulType, ExtType,
1748 TTI.getArithmeticInstrCost(Instruction::Mul, MulType,
CostKind);
1750 TTI.getCastInstrCost(RedOp->getOpcode(), VecRedTy, MulType,
1753 CostBeforeReduction = ExtCost * 2 + MulCost + Ext2Cost;
1754 CostAfterReduction =
TTI.getMulAccReductionCost(
1755 IsUnsigned, ReductionOpc,
II.getType(), ExtType,
CostKind);
1758 CostAfterReduction =
TTI.getArithmeticReductionCost(ReductionOpc, VecRedTy,
1762bool VectorCombine::foldBinopOfReductions(Instruction &
I) {
1765 if (BinOpOpc == Instruction::Sub)
1766 ReductionIID = Intrinsic::vector_reduce_add;
1770 if (ReductionIID == Intrinsic::vector_reduce_fadd ||
1771 ReductionIID == Intrinsic::vector_reduce_fmul)
1774 auto checkIntrinsicAndGetItsArgument = [](
Value *
V,
1779 if (
II->getIntrinsicID() == IID &&
II->hasOneUse())
1780 return II->getArgOperand(0);
1784 Value *V0 = checkIntrinsicAndGetItsArgument(
I.getOperand(0), ReductionIID);
1787 Value *
V1 = checkIntrinsicAndGetItsArgument(
I.getOperand(1), ReductionIID);
1792 if (
V1->getType() != VTy)
1796 unsigned ReductionOpc =
1809 CostOfRedOperand0 + CostOfRedOperand1 +
1812 if (NewCost >= OldCost || !NewCost.
isValid())
1816 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
1819 if (BinOpOpc == Instruction::Or)
1826 replaceValue(
I, *Rdx);
1834 unsigned NumScanned = 0;
1835 return std::any_of(Begin, End, [&](
const Instruction &Instr) {
1844class ScalarizationResult {
1845 enum class StatusTy { Unsafe, Safe, SafeWithFreeze };
1850 ScalarizationResult(StatusTy Status,
Value *ToFreeze =
nullptr)
1851 : Status(Status), ToFreeze(ToFreeze) {}
1854 ScalarizationResult(
const ScalarizationResult &
Other) =
default;
1855 ~ScalarizationResult() {
1856 assert(!ToFreeze &&
"freeze() not called with ToFreeze being set");
1859 static ScalarizationResult unsafe() {
return {StatusTy::Unsafe}; }
1860 static ScalarizationResult safe() {
return {StatusTy::Safe}; }
1861 static ScalarizationResult safeWithFreeze(
Value *ToFreeze) {
1862 return {StatusTy::SafeWithFreeze, ToFreeze};
1866 bool isSafe()
const {
return Status == StatusTy::Safe; }
1868 bool isUnsafe()
const {
return Status == StatusTy::Unsafe; }
1871 bool isSafeWithFreeze()
const {
return Status == StatusTy::SafeWithFreeze; }
1876 Status = StatusTy::Unsafe;
1880 void freeze(IRBuilderBase &Builder, Instruction &UserI) {
1881 assert(isSafeWithFreeze() &&
1882 "should only be used when freezing is required");
1884 "UserI must be a user of ToFreeze");
1885 IRBuilder<>::InsertPointGuard Guard(Builder);
1890 if (
U.get() == ToFreeze)
1905 uint64_t NumElements = VecTy->getElementCount().getKnownMinValue();
1909 if (
C->getValue().ult(NumElements))
1910 return ScalarizationResult::safe();
1911 return ScalarizationResult::unsafe();
1916 return ScalarizationResult::unsafe();
1918 APInt Zero(IntWidth, 0);
1919 APInt MaxElts(IntWidth, NumElements);
1926 return ScalarizationResult::safe();
1927 return ScalarizationResult::unsafe();
1940 if (ValidIndices.
contains(IdxRange))
1941 return ScalarizationResult::safeWithFreeze(IdxBase);
1942 return ScalarizationResult::unsafe();
1954 C->getZExtValue() *
DL.getTypeStoreSize(ScalarType));
1966bool VectorCombine::foldSingleElementStore(Instruction &
I) {
1978 if (!
match(
SI->getValueOperand(),
1985 Value *SrcAddr =
Load->getPointerOperand()->stripPointerCasts();
1988 if (!
Load->isSimple() ||
Load->getParent() !=
SI->getParent() ||
1989 !
DL->typeSizeEqualsStoreSize(
Load->getType()->getScalarType()) ||
1990 SrcAddr !=
SI->getPointerOperand()->stripPointerCasts())
1996 auto ScalarizableIdx =
1998 if (ScalarizableIdx.isUnsafe())
2005 if (ScalarizableIdx.isSafeWithFreeze())
2008 SI->getValueOperand()->getType(),
SI->getPointerOperand(),
2009 {ConstantInt::get(Idx->getType(), 0), Idx});
2013 std::max(
SI->getAlign(),
Load->getAlign()), NewElement->
getType(), Idx,
2016 replaceValue(
I, *NSI);
2026bool VectorCombine::scalarizeLoad(Instruction &
I) {
2036 if (!LI->isSimple() || !
DL->typeSizeEqualsStoreSize(VecTy->getScalarType()))
2039 bool AllExtracts =
true;
2040 bool AllBitcasts =
true;
2042 unsigned NumInstChecked = 0;
2047 for (User *U : LI->users()) {
2049 if (!UI || UI->getParent() != LI->getParent())
2054 if (UI->use_empty())
2058 AllExtracts =
false;
2060 AllBitcasts =
false;
2064 for (Instruction &
I :
2065 make_range(std::next(LI->getIterator()), UI->getIterator())) {
2072 LastCheckedInst = UI;
2077 return scalarizeLoadExtract(LI, VecTy, Ptr);
2079 return scalarizeLoadBitcast(LI, VecTy, Ptr);
2084bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
2089 DenseMap<ExtractElementInst *, ScalarizationResult> NeedFreeze;
2092 for (
auto &Pair : NeedFreeze)
2093 Pair.second.discard();
2101 for (User *U : LI->
users()) {
2106 if (ScalarIdx.isUnsafe())
2108 if (ScalarIdx.isSafeWithFreeze()) {
2109 NeedFreeze.try_emplace(UI, ScalarIdx);
2110 ScalarIdx.discard();
2116 Index ?
Index->getZExtValue() : -1);
2124 LLVM_DEBUG(
dbgs() <<
"Found all extractions of a vector load: " << *LI
2125 <<
"\n LoadExtractCost: " << OriginalCost
2126 <<
" vs ScalarizedCost: " << ScalarizedCost <<
"\n");
2128 if (ScalarizedCost >= OriginalCost)
2135 Type *ElemType = VecTy->getElementType();
2138 for (User *U : LI->
users()) {
2140 Value *Idx = EI->getIndexOperand();
2143 auto It = NeedFreeze.find(EI);
2144 if (It != NeedFreeze.end())
2151 Builder.
CreateLoad(ElemType,
GEP, EI->getName() +
".scalar"));
2153 Align ScalarOpAlignment =
2155 NewLoad->setAlignment(ScalarOpAlignment);
2158 size_t Offset = ConstIdx->getZExtValue() *
DL->getTypeStoreSize(ElemType);
2163 replaceValue(*EI, *NewLoad,
false);
2166 FailureGuard.release();
2171bool VectorCombine::scalarizeLoadBitcast(LoadInst *LI, VectorType *VecTy,
2177 Type *TargetScalarType =
nullptr;
2178 unsigned VecBitWidth =
DL->getTypeSizeInBits(VecTy);
2180 for (User *U : LI->
users()) {
2183 Type *DestTy = BC->getDestTy();
2187 unsigned DestBitWidth =
DL->getTypeSizeInBits(DestTy);
2188 if (DestBitWidth != VecBitWidth)
2192 if (!TargetScalarType)
2193 TargetScalarType = DestTy;
2194 else if (TargetScalarType != DestTy)
2202 if (!TargetScalarType)
2210 LLVM_DEBUG(
dbgs() <<
"Found vector load feeding only bitcasts: " << *LI
2211 <<
"\n OriginalCost: " << OriginalCost
2212 <<
" vs ScalarizedCost: " << ScalarizedCost <<
"\n");
2214 if (ScalarizedCost >= OriginalCost)
2225 ScalarLoad->copyMetadata(*LI);
2228 for (User *U : LI->
users()) {
2230 replaceValue(*BC, *ScalarLoad,
false);
2236bool VectorCombine::scalarizeExtExtract(Instruction &
I) {
2251 Type *ScalarDstTy = DstTy->getElementType();
2252 if (
DL->getTypeSizeInBits(SrcTy) !=
DL->getTypeSizeInBits(ScalarDstTy))
2258 unsigned ExtCnt = 0;
2259 bool ExtLane0 =
false;
2260 for (User *U : Ext->users()) {
2274 Instruction::And, ScalarDstTy,
CostKind,
2277 (ExtCnt - ExtLane0) *
2279 Instruction::LShr, ScalarDstTy,
CostKind,
2282 if (ScalarCost > VectorCost)
2285 Value *ScalarV = Ext->getOperand(0);
2292 SmallDenseSet<ConstantInt *, 8> ExtractedLanes;
2293 bool AllExtractsTriggerUB =
true;
2294 ExtractElementInst *LastExtract =
nullptr;
2296 for (User *U : Ext->users()) {
2299 AllExtractsTriggerUB =
false;
2303 if (!LastExtract || LastExtract->
comesBefore(Extract))
2304 LastExtract = Extract;
2306 if (ExtractedLanes.
size() != DstTy->getNumElements() ||
2307 !AllExtractsTriggerUB ||
2315 uint64_t SrcEltSizeInBits =
DL->getTypeSizeInBits(SrcTy->getElementType());
2316 uint64_t TotalBits =
DL->getTypeSizeInBits(SrcTy);
2319 Value *
Mask = ConstantInt::get(PackedTy, EltBitMask);
2320 for (User *U : Ext->users()) {
2326 ? (TotalBits - SrcEltSizeInBits - Idx * SrcEltSizeInBits)
2327 : (Idx * SrcEltSizeInBits);
2330 U->replaceAllUsesWith(
And);
2338bool VectorCombine::foldConcatOfBoolMasks(Instruction &
I) {
2339 Type *Ty =
I.getType();
2344 if (
DL->isBigEndian())
2355 uint64_t ShAmtX = 0;
2363 uint64_t ShAmtY = 0;
2371 if (ShAmtX > ShAmtY) {
2379 uint64_t ShAmtDiff = ShAmtY - ShAmtX;
2380 unsigned NumSHL = (ShAmtX > 0) + (ShAmtY > 0);
2385 MaskTy->getNumElements() != ShAmtDiff ||
2386 MaskTy->getNumElements() > (
BitWidth / 2))
2391 Type::getIntNTy(Ty->
getContext(), ConcatTy->getNumElements());
2392 auto *MaskIntTy = Type::getIntNTy(Ty->
getContext(), ShAmtDiff);
2395 std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
2412 if (Ty != ConcatIntTy)
2418 LLVM_DEBUG(
dbgs() <<
"Found a concatenation of bitcasted bool masks: " <<
I
2419 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2422 if (NewCost > OldCost)
2432 if (Ty != ConcatIntTy) {
2442 replaceValue(
I, *Result);
2448bool VectorCombine::foldPermuteOfBinops(Instruction &
I) {
2449 BinaryOperator *BinOp;
2450 ArrayRef<int> OuterMask;
2458 Value *Op00, *Op01, *Op10, *Op11;
2459 ArrayRef<int> Mask0, Mask1;
2464 if (!Match0 && !Match1)
2477 if (!ShuffleDstTy || !BinOpTy || !Op0Ty || !Op1Ty)
2480 unsigned NumSrcElts = BinOpTy->getNumElements();
2485 any_of(OuterMask, [NumSrcElts](
int M) {
return M >= (int)NumSrcElts; }))
2489 SmallVector<int> NewMask0, NewMask1;
2490 for (
int M : OuterMask) {
2491 if (M < 0 || M >= (
int)NumSrcElts) {
2495 NewMask0.
push_back(Match0 ? Mask0[M] : M);
2496 NewMask1.
push_back(Match1 ? Mask1[M] : M);
2500 unsigned NumOpElts = Op0Ty->getNumElements();
2501 bool IsIdentity0 = ShuffleDstTy == Op0Ty &&
2502 all_of(NewMask0, [NumOpElts](
int M) {
return M < (int)NumOpElts; }) &&
2504 bool IsIdentity1 = ShuffleDstTy == Op1Ty &&
2505 all_of(NewMask1, [NumOpElts](
int M) {
return M < (int)NumOpElts; }) &&
2514 ShuffleDstTy, BinOpTy, OuterMask,
CostKind,
2515 0,
nullptr, {BinOp}, &
I);
2517 NewCost += BinOpCost;
2523 OldCost += Shuf0Cost;
2525 NewCost += Shuf0Cost;
2531 OldCost += Shuf1Cost;
2533 NewCost += Shuf1Cost;
2541 Op0Ty, NewMask0,
CostKind, 0,
nullptr, {Op00, Op01});
2545 Op1Ty, NewMask1,
CostKind, 0,
nullptr, {Op10, Op11});
2547 LLVM_DEBUG(
dbgs() <<
"Found a shuffle feeding a shuffled binop: " <<
I
2548 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2552 if (NewCost > OldCost)
2563 NewInst->copyIRFlags(BinOp);
2567 replaceValue(
I, *NewBO);
2573bool VectorCombine::foldShuffleOfBinops(Instruction &
I) {
2574 ArrayRef<int> OldMask;
2581 if (
LHS->getOpcode() !=
RHS->getOpcode())
2585 bool IsCommutative =
false;
2594 IsCommutative = BinaryOperator::isCommutative(BO->getOpcode());
2605 if (!ShuffleDstTy || !BinResTy || !BinOpTy ||
X->getType() !=
Z->getType())
2608 bool SameBinOp =
LHS ==
RHS;
2609 unsigned NumSrcElts = BinOpTy->getNumElements();
2612 if (IsCommutative &&
X != Z &&
Y != W && (
X == W ||
Y == Z))
2615 auto ConvertToUnary = [NumSrcElts](
int &
M) {
2616 if (M >= (
int)NumSrcElts)
2620 SmallVector<int> NewMask0(OldMask);
2629 SmallVector<int> NewMask1(OldMask);
2648 ShuffleDstTy, BinResTy, OldMask,
CostKind, 0,
2658 ArrayRef<int> InnerMask;
2660 m_Mask(InnerMask)))) &&
2663 [NumSrcElts](
int M) {
return M < (int)NumSrcElts; })) {
2675 bool ReducedInstCount =
false;
2676 ReducedInstCount |= MergeInner(
X, 0, NewMask0,
CostKind);
2677 ReducedInstCount |= MergeInner(
Y, 0, NewMask1,
CostKind);
2678 ReducedInstCount |= MergeInner(Z, NumSrcElts, NewMask0,
CostKind);
2679 ReducedInstCount |= MergeInner(W, NumSrcElts, NewMask1,
CostKind);
2680 bool SingleSrcBinOp = (
X ==
Y) && (Z == W) && (NewMask0 == NewMask1);
2692 I.getType()->getScalarType()->isIntegerTy(1) &&
2696 auto *ShuffleCmpTy =
2699 SK0, ShuffleCmpTy, BinOpTy, NewMask0,
CostKind, 0,
nullptr, {
X,
Z});
2700 if (!SingleSrcBinOp)
2710 PredLHS,
CostKind, Op0Info, Op1Info);
2720 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2727 if (ReducedInstCount ? (NewCost > OldCost) : (NewCost >= OldCost))
2736 : Builder.
CreateCmp(PredLHS, Shuf0, Shuf1);
2740 NewInst->copyIRFlags(
LHS);
2741 NewInst->andIRFlags(
RHS);
2746 replaceValue(
I, *NewBO);
2753bool VectorCombine::foldShuffleOfSelects(Instruction &
I) {
2755 Value *C1, *
T1, *F1, *C2, *T2, *F2;
2766 if (!C1VecTy || !C2VecTy || C1VecTy != C2VecTy)
2772 if (((SI0FOp ==
nullptr) != (SI1FOp ==
nullptr)) ||
2773 ((SI0FOp !=
nullptr) &&
2774 (SI0FOp->getFastMathFlags() != SI1FOp->getFastMathFlags())))
2780 auto SelOp = Instruction::Select;
2788 CostSel1 + CostSel2 +
2790 {
I.getOperand(0),
I.getOperand(1)}, &
I);
2794 Mask,
CostKind, 0,
nullptr, {C1, C2});
2804 if (!Sel1->hasOneUse())
2805 NewCost += CostSel1;
2806 if (!Sel2->hasOneUse())
2807 NewCost += CostSel2;
2810 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2812 if (NewCost > OldCost)
2821 NewSel = Builder.
CreateSelectFMF(ShuffleCmp, ShuffleTrue, ShuffleFalse,
2822 SI0FOp->getFastMathFlags());
2824 NewSel = Builder.
CreateSelect(ShuffleCmp, ShuffleTrue, ShuffleFalse);
2829 replaceValue(
I, *NewSel);
2835bool VectorCombine::foldShuffleOfCastops(Instruction &
I) {
2837 ArrayRef<int> OldMask;
2846 if (!C0 || (IsBinaryShuffle && !C1))
2853 if (!IsBinaryShuffle && Opcode == Instruction::BitCast)
2856 if (IsBinaryShuffle) {
2857 if (C0->getSrcTy() != C1->getSrcTy())
2860 if (Opcode != C1->getOpcode()) {
2862 Opcode = Instruction::SExt;
2871 if (!ShuffleDstTy || !CastDstTy || !CastSrcTy)
2874 unsigned NumSrcElts = CastSrcTy->getNumElements();
2875 unsigned NumDstElts = CastDstTy->getNumElements();
2876 assert((NumDstElts == NumSrcElts || Opcode == Instruction::BitCast) &&
2877 "Only bitcasts expected to alter src/dst element counts");
2881 if (NumDstElts != NumSrcElts && (NumSrcElts % NumDstElts) != 0 &&
2882 (NumDstElts % NumSrcElts) != 0)
2885 SmallVector<int, 16> NewMask;
2886 if (NumSrcElts >= NumDstElts) {
2889 assert(NumSrcElts % NumDstElts == 0 &&
"Unexpected shuffle mask");
2890 unsigned ScaleFactor = NumSrcElts / NumDstElts;
2895 assert(NumDstElts % NumSrcElts == 0 &&
"Unexpected shuffle mask");
2896 unsigned ScaleFactor = NumDstElts / NumSrcElts;
2901 auto *NewShuffleDstTy =
2910 if (IsBinaryShuffle)
2925 if (IsBinaryShuffle) {
2935 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
2937 if (NewCost > OldCost)
2941 if (IsBinaryShuffle)
2951 NewInst->copyIRFlags(C0);
2952 if (IsBinaryShuffle)
2953 NewInst->andIRFlags(C1);
2957 replaceValue(
I, *Cast);
2967bool VectorCombine::foldShuffleOfShuffles(Instruction &
I) {
2968 ArrayRef<int> OuterMask;
2969 Value *OuterV0, *OuterV1;
2974 ArrayRef<int> InnerMask0, InnerMask1;
2975 Value *X0, *X1, *Y0, *Y1;
2980 if (!Match0 && !Match1)
2985 SmallVector<int, 16> PoisonMask1;
2990 InnerMask1 = PoisonMask1;
2994 X0 = Match0 ? X0 : OuterV0;
2995 Y0 = Match0 ? Y0 : OuterV0;
2996 X1 = Match1 ? X1 : OuterV1;
2997 Y1 = Match1 ? Y1 : OuterV1;
3001 if (!ShuffleDstTy || !ShuffleSrcTy || !ShuffleImmTy ||
3005 unsigned NumSrcElts = ShuffleSrcTy->getNumElements();
3006 unsigned NumImmElts = ShuffleImmTy->getNumElements();
3011 SmallVector<int, 16> NewMask(OuterMask);
3012 Value *NewX =
nullptr, *NewY =
nullptr;
3013 for (
int &M : NewMask) {
3014 Value *Src =
nullptr;
3015 if (0 <= M && M < (
int)NumImmElts) {
3019 Src =
M >= (int)NumSrcElts ? Y0 : X0;
3020 M =
M >= (int)NumSrcElts ? (M - NumSrcElts) :
M;
3022 }
else if (M >= (
int)NumImmElts) {
3027 Src =
M >= (int)NumSrcElts ? Y1 : X1;
3028 M =
M >= (int)NumSrcElts ? (M - NumSrcElts) :
M;
3032 assert(0 <= M && M < (
int)NumSrcElts &&
"Unexpected shuffle mask index");
3041 if (!NewX || NewX == Src) {
3045 if (!NewY || NewY == Src) {
3064 replaceValue(
I, *NewX);
3081 bool IsUnary =
all_of(NewMask, [&](
int M) {
return M < (int)NumSrcElts; });
3087 nullptr, {NewX, NewY});
3089 NewCost += InnerCost0;
3091 NewCost += InnerCost1;
3094 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
3096 if (NewCost > OldCost)
3100 replaceValue(
I, *Shuf);
3116bool VectorCombine::foldShufflesOfLengthChangingShuffles(Instruction &
I) {
3121 unsigned ChainLength = 0;
3122 SmallVector<int>
Mask;
3123 SmallVector<int> YMask;
3133 ArrayRef<int> OuterMask;
3134 Value *OuterV0, *OuterV1;
3135 if (ChainLength != 0 && !Trunk->
hasOneUse())
3138 m_Mask(OuterMask))))
3140 if (OuterV0->
getType() != TrunkType) {
3146 ArrayRef<int> InnerMask0, InnerMask1;
3147 Value *A0, *A1, *B0, *B1;
3152 bool Match0Leaf = Match0 && A0->
getType() !=
I.getType();
3153 bool Match1Leaf = Match1 && A1->
getType() !=
I.getType();
3154 if (Match0Leaf == Match1Leaf) {
3160 SmallVector<int> CommutedOuterMask;
3167 for (
int &M : CommutedOuterMask) {
3170 if (M < (
int)NumTrunkElts)
3175 OuterMask = CommutedOuterMask;
3194 int NumLeafElts = YType->getNumElements();
3195 SmallVector<int> LocalYMask(InnerMask1);
3196 for (
int &M : LocalYMask) {
3197 if (M >= NumLeafElts)
3207 Mask.assign(OuterMask);
3208 YMask.
assign(LocalYMask);
3209 OldCost = NewCost = LocalOldCost;
3216 SmallVector<int> NewYMask(YMask);
3218 for (
auto [CombinedM, LeafM] :
llvm::zip(NewYMask, LocalYMask)) {
3219 if (LeafM == -1 || CombinedM == LeafM)
3221 if (CombinedM == -1) {
3231 SmallVector<int> NewMask;
3232 NewMask.
reserve(NumTrunkElts);
3233 for (
int M : Mask) {
3234 if (M < 0 || M >=
static_cast<int>(NumTrunkElts))
3249 if (LocalNewCost >= NewCost && LocalOldCost < LocalNewCost - NewCost)
3253 if (ChainLength == 1) {
3254 dbgs() <<
"Found chain of shuffles fed by length-changing shuffles: "
3257 dbgs() <<
" next chain link: " << *Trunk <<
'\n'
3258 <<
" old cost: " << (OldCost + LocalOldCost)
3259 <<
" new cost: " << LocalNewCost <<
'\n';
3264 OldCost += LocalOldCost;
3265 NewCost = LocalNewCost;
3269 if (ChainLength <= 1)
3277 return M < 0 || M >=
static_cast<int>(NumTrunkElts);
3280 for (
int &M : Mask) {
3281 if (M >=
static_cast<int>(NumTrunkElts))
3282 M = YMask[
M - NumTrunkElts];
3286 replaceValue(
I, *Root);
3293 replaceValue(
I, *Root);
3299bool VectorCombine::foldShuffleOfIntrinsics(Instruction &
I) {
3301 ArrayRef<int> OldMask;
3311 if (IID != II1->getIntrinsicID())
3320 if (!ShuffleDstTy || !II0Ty)
3326 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3327 Value *Arg0 = II0->getArgOperand(
I);
3328 Value *Arg1 = II1->getArgOperand(
I);
3345 II0Ty, OldMask,
CostKind, 0,
nullptr, {II0, II1}, &
I);
3349 SmallDenseSet<std::pair<Value *, Value *>> SeenOperandPairs;
3350 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3352 NewArgsTy.
push_back(II0->getArgOperand(
I)->getType());
3356 ShuffleDstTy->getNumElements());
3358 std::pair<Value *, Value *> OperandPair =
3359 std::make_pair(II0->getArgOperand(
I), II1->getArgOperand(
I));
3360 if (!SeenOperandPairs.
insert(OperandPair).second) {
3366 CostKind, 0,
nullptr, {II0->getArgOperand(
I), II1->getArgOperand(
I)});
3369 IntrinsicCostAttributes NewAttr(IID, ShuffleDstTy, NewArgsTy);
3372 if (!II0->hasOneUse())
3374 if (II1 != II0 && !II1->hasOneUse())
3378 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
3381 if (NewCost > OldCost)
3385 SmallDenseMap<std::pair<Value *, Value *>,
Value *> ShuffleCache;
3386 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I)
3390 std::pair<Value *, Value *> OperandPair =
3391 std::make_pair(II0->getArgOperand(
I), II1->getArgOperand(
I));
3392 auto It = ShuffleCache.
find(OperandPair);
3393 if (It != ShuffleCache.
end()) {
3399 II1->getArgOperand(
I), OldMask);
3400 ShuffleCache[OperandPair] = Shuf;
3408 NewInst->copyIRFlags(II0);
3409 NewInst->andIRFlags(II1);
3412 replaceValue(
I, *NewIntrinsic);
3418bool VectorCombine::foldPermuteOfIntrinsic(Instruction &
I) {
3430 if (!ShuffleDstTy || !IntrinsicSrcTy)
3434 unsigned NumSrcElts = IntrinsicSrcTy->getNumElements();
3435 if (
any_of(Mask, [NumSrcElts](
int M) {
return M >= (int)NumSrcElts; }))
3448 IntrinsicSrcTy, Mask,
CostKind, 0,
nullptr, {V0}, &
I);
3452 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3454 NewArgsTy.
push_back(II0->getArgOperand(
I)->getType());
3458 ShuffleDstTy->getNumElements());
3461 ArgTy, VecTy, Mask,
CostKind, 0,
nullptr,
3462 {II0->getArgOperand(
I)});
3465 IntrinsicCostAttributes NewAttr(IID, ShuffleDstTy, NewArgsTy);
3470 if (!II0->hasOneUse())
3473 LLVM_DEBUG(
dbgs() <<
"Found a permute of intrinsic: " <<
I <<
"\n OldCost: "
3474 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
3476 if (NewCost > OldCost)
3481 for (
unsigned I = 0,
E = II0->arg_size();
I !=
E; ++
I) {
3494 NewInst->copyIRFlags(II0);
3496 replaceValue(
I, *NewIntrinsic);
3506 int M = SV->getMaskValue(Lane);
3509 if (
static_cast<unsigned>(M) < NumElts) {
3510 V = SV->getOperand(0);
3513 V = SV->getOperand(1);
3524 auto [U, Lane] = IL;
3537 unsigned NumElts = Ty->getNumElements();
3538 if (Item.
size() == NumElts || NumElts == 1 || Item.
size() % NumElts != 0)
3544 std::iota(ConcatMask.
begin(), ConcatMask.
end(), 0);
3550 unsigned NumSlices = Item.
size() / NumElts;
3555 for (
unsigned Slice = 0; Slice < NumSlices; ++Slice) {
3556 Value *SliceV = Item[Slice * NumElts].first;
3557 if (!SliceV || SliceV->
getType() != Ty)
3559 for (
unsigned Elt = 0; Elt < NumElts; ++Elt) {
3560 auto [V, Lane] = Item[Slice * NumElts + Elt];
3561 if (Lane !=
static_cast<int>(Elt) || SliceV != V)
3570 const DenseSet<std::pair<Value *, Use *>> &IdentityLeafs,
3571 const DenseSet<std::pair<Value *, Use *>> &SplatLeafs,
3572 const DenseSet<std::pair<Value *, Use *>> &ConcatLeafs,
3575 auto [FrontV, FrontLane] = Item.
front();
3577 if (IdentityLeafs.contains(std::make_pair(FrontV, From))) {
3580 if (SplatLeafs.contains(std::make_pair(FrontV, From))) {
3582 return Builder.CreateShuffleVector(FrontV, Mask);
3584 if (ConcatLeafs.contains(std::make_pair(FrontV, From))) {
3588 for (
unsigned S = 0; S <
Values.size(); ++S)
3589 Values[S] = Item[S * NumElts].first;
3591 while (
Values.size() > 1) {
3594 std::iota(Mask.begin(), Mask.end(), 0);
3596 for (
unsigned S = 0; S < NewValues.
size(); ++S)
3598 Builder.CreateShuffleVector(
Values[S * 2],
Values[S * 2 + 1], Mask);
3612 if (BCDstTy && BCSrcTy &&
3613 BCDstTy->getElementCount() != BCSrcTy->getElementCount()) {
3614 unsigned DstElts = BCDstTy->getNumElements();
3615 unsigned SrcElts = BCSrcTy->getNumElements();
3617 if (DstElts > SrcElts) {
3619 unsigned R = DstElts / SrcElts;
3620 if (Item.
size() % R != 0)
3622 for (
unsigned Idx = 0,
E = Item.
size(); Idx <
E; Idx += R) {
3623 auto [V, Lane] = Item[Idx];
3633 unsigned R = SrcElts / DstElts;
3634 for (
auto [V, Lane] : Item) {
3640 for (
unsigned J = 0; J < R; ++J)
3645 IdentityLeafs, SplatLeafs, ConcatLeafs,
3646 Builder, WorkList,
TTI);
3648 return Builder.CreateBitCast(
3653 unsigned NumOps =
I->getNumOperands() - (
II ? 1 : 0);
3655 for (
unsigned Idx = 0; Idx <
NumOps; Idx++) {
3658 Ops[Idx] =
II->getOperand(Idx);
3663 IdentityLeafs, SplatLeafs, ConcatLeafs, Builder, WorkList,
TTI);
3673 for (
const auto &Lane : Item)
3686 auto *
Value = Builder.CreateCmp(CI->getPredicate(),
Ops[0],
Ops[1]);
3696 auto *
Value = Builder.CreateCast(CI->getOpcode(),
Ops[0], DstTy);
3701 auto *
Value = Builder.CreateIntrinsic(DstTy,
II->getIntrinsicID(),
Ops);
3715bool VectorCombine::foldShuffleToIdentity(Instruction &
I) {
3717 if (!Ty ||
I.use_empty())
3721 for (
unsigned M = 0,
E = Ty->getNumElements(); M <
E; ++M)
3725 Candidates.
push_back(std::make_pair(Start, &*
I.use_begin()));
3726 DenseSet<std::pair<Value *, Use *>> IdentityLeafs, SplatLeafs, ConcatLeafs;
3727 unsigned NumVisited = 0;
3728 bool TraversedElCountChangingBitcast =
false;
3730 while (!Candidates.
empty()) {
3735 auto Item = ItemFrom.first;
3736 auto From = ItemFrom.second;
3737 auto [FrontV, FrontLane] = Item.front();
3745 return X->getType() ==
Y->getType() &&
3750 if (FrontLane == 0 &&
3754 Value *FrontV = Item.front().first;
3755 return !
E.value().first || (IsEquiv(
E.value().first, FrontV) &&
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 (Cut || (!IsIdempotent && !It->second.Duplicates.isZero())) {
4274 Cut = ReductionCut{S, It->second.Lanes};
4277 for (
Value *V : Nodes) {
4280 auto It = Demands.
find(V);
4281 if (It == Demands.
end() || !It->second.Lanes.isAllOnes())
4283 if (!IsIdempotent && !It->second.Duplicates.isZero())
4285 if (!CoversChain(V))
4287 Cut = ReductionCut{
V, It->second.Lanes};
4292 if (!Cut || Cut->Elts.popcount() < 2)
4302 for (
Value *V : Nodes)
4306 bool IsPartialReduction = !Cut->Elts.isAllOnes();
4307 FixedVectorType *ReduceVecTy =
4312 SmallVector<int> ExtractMask;
4314 if (IsPartialReduction) {
4315 for (
unsigned I = 0,
E = Cut->Elts.getBitWidth();
I !=
E; ++
I)
4317 ExtractMask.push_back(
I);
4318 unsigned SubIdx = 0, SubLen;
4319 auto SK = Cut->Elts.isShiftedMask(SubIdx, SubLen)
4323 SubIdx, ReduceVecTy);
4326 IntrinsicCostAttributes ICA(
4327 ReducedOp, ReduceVecTy->getElementType(),
4331 IsFloatReduction ? CommonFMF : FastMathFlags());
4334 LLVM_DEBUG(
dbgs() <<
"Found reduction shuffle chain: " <<
I <<
"\n OldCost : "
4335 << OrigCost <<
" vs NewCost: " << NewCost <<
"\n");
4340 if (VecOpEE->
hasOneUse() ? (NewCost > OrigCost) : (NewCost >= OrigCost))
4343 Value *ReduceInput = Cut->Src;
4344 if (IsPartialReduction)
4347 Value *ReducedResult;
4348 if (IsFloatReduction) {
4350 *CommonBinOp, ReduceVecTy->getElementType(),
false,
4353 {Identity, ReduceInput}, CommonFMF);
4358 replaceValue(
I, *ReducedResult);
4367bool VectorCombine::foldCastFromReductions(Instruction &
I) {
4372 bool TruncOnly =
false;
4375 case Intrinsic::vector_reduce_add:
4376 case Intrinsic::vector_reduce_mul:
4379 case Intrinsic::vector_reduce_and:
4380 case Intrinsic::vector_reduce_or:
4381 case Intrinsic::vector_reduce_xor:
4388 Value *ReductionSrc =
I.getOperand(0);
4400 Type *ResultTy =
I.getType();
4403 ReductionOpc, ReductionSrcTy, std::nullopt,
CostKind);
4413 if (OldCost <= NewCost || !NewCost.
isValid())
4417 II->getIntrinsicID(), {Src});
4419 replaceValue(
I, *NewCast);
4447bool VectorCombine::foldSignBitReductionCmp(Instruction &
I) {
4449 IntrinsicInst *ReduceOp;
4450 const APInt *CmpVal;
4457 case Intrinsic::vector_reduce_or:
4458 case Intrinsic::vector_reduce_umax:
4459 case Intrinsic::vector_reduce_and:
4460 case Intrinsic::vector_reduce_umin:
4461 case Intrinsic::vector_reduce_add:
4472 unsigned BitWidth = VecTy->getScalarSizeInBits();
4476 unsigned NumElts = VecTy->getNumElements();
4485 case Intrinsic::vector_reduce_or:
4486 case Intrinsic::vector_reduce_umax:
4487 TreeOpcode = Instruction::Or;
4489 case Intrinsic::vector_reduce_and:
4490 case Intrinsic::vector_reduce_umin:
4491 TreeOpcode = Instruction::And;
4493 case Intrinsic::vector_reduce_add:
4494 TreeOpcode = Instruction::Add;
4502 SmallVector<Value *, 8> Worklist;
4503 SmallVector<Value *, 8> Sources;
4505 std::optional<bool> IsAShr;
4506 constexpr unsigned MaxSources = 8;
4511 while (!Worklist.
empty() && Worklist.
size() <= MaxSources &&
4512 Sources.
size() <= MaxSources) {
4521 bool ThisIsAShr = Shr->getOpcode() == Instruction::AShr;
4523 IsAShr = ThisIsAShr;
4524 else if (*IsAShr != ThisIsAShr)
4550 if (Sources.
empty() || Sources.
size() > MaxSources ||
4551 Worklist.
size() > MaxSources || !IsAShr)
4554 unsigned NumSources = Sources.
size();
4558 if (OrigIID == Intrinsic::vector_reduce_add &&
4566 (OrigIID == Intrinsic::vector_reduce_add) ? NumSources * NumElts : 1;
4569 NegativeVal.negate();
4601 TestsNegative =
false;
4602 }
else if (*CmpVal == NegativeVal) {
4603 TestsNegative =
true;
4607 IsEq = Pred == ICmpInst::ICMP_EQ;
4608 }
else if (Pred == ICmpInst::ICMP_SLT && *CmpVal == RangeHigh) {
4610 TestsNegative = (RangeHigh == NegativeVal);
4611 }
else if (Pred == ICmpInst::ICMP_SGT && *CmpVal == RangeHigh - 1) {
4613 TestsNegative = (RangeHigh == NegativeVal);
4614 }
else if (Pred == ICmpInst::ICMP_SGT && *CmpVal == RangeLow) {
4616 TestsNegative = (RangeLow == NegativeVal);
4617 }
else if (Pred == ICmpInst::ICMP_SLT && *CmpVal == RangeLow + 1) {
4619 TestsNegative = (RangeLow == NegativeVal);
4662 enum CheckKind :
unsigned {
4669 auto RequiresOr = [](CheckKind
C) ->
bool {
return C & 0b100; };
4671 auto IsNegativeCheck = [](CheckKind
C) ->
bool {
return C & 0b010; };
4673 auto Invert = [](CheckKind
C) {
return CheckKind(
C ^ 0b011); };
4677 case Intrinsic::vector_reduce_or:
4678 case Intrinsic::vector_reduce_umax:
4679 Base = TestsNegative ? AnyNeg : AllNonNeg;
4681 case Intrinsic::vector_reduce_and:
4682 case Intrinsic::vector_reduce_umin:
4683 Base = TestsNegative ? AllNeg : AnyNonNeg;
4685 case Intrinsic::vector_reduce_add:
4686 Base = TestsNegative ? AllNeg : AllNonNeg;
4701 return ArithCost <= MinMaxCost ? std::make_pair(Arith, ArithCost)
4702 : std::make_pair(MinMax, MinMaxCost);
4706 auto [NewIID, NewCost] = RequiresOr(
Check)
4707 ? PickCheaper(Intrinsic::vector_reduce_or,
4708 Intrinsic::vector_reduce_umax)
4709 : PickCheaper(
Intrinsic::vector_reduce_and,
4713 if (NumSources > 1) {
4714 unsigned CombineOpc =
4715 RequiresOr(
Check) ? Instruction::Or : Instruction::And;
4720 LLVM_DEBUG(
dbgs() <<
"Found sign-bit reduction cmp: " <<
I <<
"\n OldCost: "
4721 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
4723 if (NewCost > OldCost)
4728 Type *ScalarTy = VecTy->getScalarType();
4731 if (NumSources == 1) {
4742 replaceValue(
I, *NewCmp);
4773bool VectorCombine::foldReductionZeroTest(Instruction &
I) {
4782 if (!
II || !
II->hasOneUse())
4785 auto ReduceID =
II->getIntrinsicID();
4786 if (ReduceID != Intrinsic::vector_reduce_or &&
4787 ReduceID != Intrinsic::vector_reduce_umax)
4790 Value *Vec =
II->getArgOperand(0);
4792 if (!VecTy || !VecTy->getElementType()->isIntegerTy())
4797 ? Intrinsic::vector_reduce_or
4812 LLVM_DEBUG(
dbgs() <<
"Found a reduction zero test: " <<
I <<
"\n OldCost: "
4813 << OldCost <<
" vs NewCost: " << NewCost <<
"\n");
4815 if (!OldCost.
isValid() || !NewCost.
isValid() || NewCost > OldCost)
4821 replaceValue(
I, *NewReduce);
4846bool VectorCombine::foldICmpEqZeroVectorReduce(Instruction &
I) {
4857 switch (
II->getIntrinsicID()) {
4858 case Intrinsic::vector_reduce_add:
4859 case Intrinsic::vector_reduce_or:
4860 case Intrinsic::vector_reduce_umin:
4861 case Intrinsic::vector_reduce_umax:
4862 case Intrinsic::vector_reduce_smin:
4863 case Intrinsic::vector_reduce_smax:
4869 Value *InnerOp =
II->getArgOperand(0);
4912 switch (
II->getIntrinsicID()) {
4913 case Intrinsic::vector_reduce_add: {
4918 unsigned NumElems = XTy->getNumElements();
4924 if (LeadingZerosX <= LostBits || LeadingZerosFX <= LostBits)
4932 case Intrinsic::vector_reduce_smin:
4933 case Intrinsic::vector_reduce_smax:
4943 LLVM_DEBUG(
dbgs() <<
"Found a reduction to 0 comparison with removable op: "
4959 case Intrinsic::vector_reduce_add:
4960 case Intrinsic::vector_reduce_or:
4966 case Intrinsic::vector_reduce_umin:
4967 case Intrinsic::vector_reduce_umax:
4968 case Intrinsic::vector_reduce_smin:
4969 case Intrinsic::vector_reduce_smax:
4981 NewReduceCost + (InnerOp->
hasOneUse() ? 0 : ExtCost);
4983 LLVM_DEBUG(
dbgs() <<
"Found a removable extension before reduction: "
4984 << *InnerOp <<
"\n OldCost: " << OldCost
4985 <<
" vs NewCost: " << NewCost <<
"\n");
4991 if (NewCost > OldCost)
5000 Builder.
CreateICmp(Pred, NewReduce, ConstantInt::getNullValue(Ty));
5001 replaceValue(
I, *NewCmp);
5032bool VectorCombine::foldEquivalentReductionCmp(Instruction &
I) {
5035 const APInt *CmpVal;
5040 if (!
II || !
II->hasOneUse())
5043 const auto IsValidOrUmaxCmp = [&]() {
5052 bool IsPositive = CmpVal->
isAllOnes() && Pred == ICmpInst::ICMP_SGT;
5054 bool IsNegative = (CmpVal->
isZero() || CmpVal->
isOne() || *CmpVal == 2) &&
5055 Pred == ICmpInst::ICMP_SLT;
5056 return IsEquality || IsPositive || IsNegative;
5059 const auto IsValidAndUminCmp = [&]() {
5064 const auto LeadingOnes = CmpVal->
countl_one();
5071 bool IsNegative = CmpVal->
isZero() && Pred == ICmpInst::ICMP_SLT;
5080 ((*CmpVal)[0] || (*CmpVal)[1]) && Pred == ICmpInst::ICMP_SGT;
5081 return IsEquality || IsNegative || IsPositive;
5089 switch (OriginalIID) {
5090 case Intrinsic::vector_reduce_or:
5091 if (!IsValidOrUmaxCmp())
5093 AlternativeIID = Intrinsic::vector_reduce_umax;
5095 case Intrinsic::vector_reduce_umax:
5096 if (!IsValidOrUmaxCmp())
5098 AlternativeIID = Intrinsic::vector_reduce_or;
5100 case Intrinsic::vector_reduce_and:
5101 if (!IsValidAndUminCmp())
5103 AlternativeIID = Intrinsic::vector_reduce_umin;
5105 case Intrinsic::vector_reduce_umin:
5106 if (!IsValidAndUminCmp())
5108 AlternativeIID = Intrinsic::vector_reduce_and;
5121 if (ReductionOpc != Instruction::ICmp)
5132 <<
"\n OrigCost: " << OrigCost
5133 <<
" vs AltCost: " << AltCost <<
"\n");
5135 if (AltCost >= OrigCost)
5139 Type *ScalarTy = VecTy->getScalarType();
5142 Builder.
CreateICmp(Pred, NewReduce, ConstantInt::get(ScalarTy, *CmpVal));
5144 replaceValue(
I, *NewCmp);
5158 unsigned Depth = 0) {
5159 constexpr unsigned MaxLocalDepth = 2;
5160 if (
Depth > MaxLocalDepth)
5163 auto NumSignBits = [&](
const Value *
X) {
5166 if (NumSignBits(V) == V->getType()->getScalarSizeInBits())
5171 return NumSignBits(
A) >= 2 && NumSignBits(
B) >= 2 &&
5182bool VectorCombine::foldReduceAddCmpZero(Instruction &
I) {
5192 if (!VecTy || VecTy->getNumElements() < 2)
5198 if (!IsNonNegative && !IsNonPositive)
5203 unsigned NumElts = VecTy->getNumElements();
5205 if (
Log2_32(NumElts) >= NumSignBits)
5208 ICmpInst::Predicate NewPred;
5210 case ICmpInst::ICMP_EQ:
5211 case ICmpInst::ICMP_ULE:
5212 case ICmpInst::ICMP_SLE:
5213 case ICmpInst::ICMP_SGE:
5214 NewPred = ICmpInst::ICMP_EQ;
5216 case ICmpInst::ICMP_NE:
5217 case ICmpInst::ICMP_UGT:
5218 case ICmpInst::ICMP_SGT:
5219 case ICmpInst::ICMP_SLT:
5220 NewPred = ICmpInst::ICMP_NE;
5230 if (!IsNonNegative &&
5231 (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLE))
5233 if (!IsNonPositive &&
5234 (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGE))
5236 if ((Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLE ||
5237 Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGE) &&
5238 Log2_32(NumElts) >= NumSignBits - 1)
5242 Instruction::Add, VecTy, std::nullopt,
CostKind);
5244 Instruction::Or, VecTy, std::nullopt,
CostKind);
5246 Intrinsic::umax, VecTy, FastMathFlags(),
CostKind);
5249 bool UseOr = OrCost.
isValid() && (!UmaxCost.
isValid() || OrCost <= UmaxCost);
5251 if (AltCost > OrigCost)
5257 Intrinsic::vector_reduce_umax, {VecTy}, {Vec});
5258 Worklist.pushValue(NewReduce);
5260 NewPred, NewReduce, ConstantInt::getNullValue(VecTy->getScalarType()));
5261 replaceValue(
I, *NewCmp);
5270 constexpr unsigned MaxVisited = 32;
5273 bool FoundReduction =
false;
5276 while (!WorkList.
empty()) {
5278 for (
User *U :
I->users()) {
5280 if (!UI || !Visited.
insert(UI).second)
5282 if (Visited.
size() > MaxVisited)
5288 switch (
II->getIntrinsicID()) {
5289 case Intrinsic::vector_reduce_add:
5290 case Intrinsic::vector_reduce_mul:
5291 case Intrinsic::vector_reduce_and:
5292 case Intrinsic::vector_reduce_or:
5293 case Intrinsic::vector_reduce_xor:
5294 case Intrinsic::vector_reduce_smin:
5295 case Intrinsic::vector_reduce_smax:
5296 case Intrinsic::vector_reduce_umin:
5297 case Intrinsic::vector_reduce_umax:
5298 FoundReduction =
true;
5311 return FoundReduction;
5324bool VectorCombine::foldSelectShuffle(Instruction &
I,
bool FromReduction) {
5329 if (!Op0 || !Op1 || Op0 == Op1 || !Op0->isBinaryOp() || !Op1->isBinaryOp() ||
5337 SmallPtrSet<Instruction *, 4> InputShuffles({SVI0A, SVI0B, SVI1A, SVI1B});
5339 if (!
I ||
I->getOperand(0)->getType() != VT)
5341 return any_of(
I->users(), [&](User *U) {
5342 return U != Op0 && U != Op1 &&
5343 !(isa<ShuffleVectorInst>(U) &&
5344 (InputShuffles.contains(cast<Instruction>(U)) ||
5345 isInstructionTriviallyDead(cast<Instruction>(U))));
5348 if (checkSVNonOpUses(SVI0A) || checkSVNonOpUses(SVI0B) ||
5349 checkSVNonOpUses(SVI1A) || checkSVNonOpUses(SVI1B))
5357 for (
auto *U :
I->users()) {
5359 if (!SV || SV->getType() != VT)
5361 if ((SV->getOperand(0) != Op0 && SV->getOperand(0) != Op1) ||
5362 (SV->getOperand(1) != Op0 && SV->getOperand(1) != Op1))
5369 if (!collectShuffles(Op0) || !collectShuffles(Op1))
5373 if (FromReduction && Shuffles.
size() > 1)
5378 if (!FromReduction) {
5379 for (
size_t Idx = 0,
E = Shuffles.
size(); Idx !=
E; ++Idx) {
5380 for (
auto *U : Shuffles[Idx]->
users()) {
5395 int MaxV1Elt = 0, MaxV2Elt = 0;
5396 unsigned NumElts = VT->getNumElements();
5397 for (ShuffleVectorInst *SVN : Shuffles) {
5398 SmallVector<int>
Mask;
5399 SVN->getShuffleMask(Mask);
5403 Value *SVOp0 = SVN->getOperand(0);
5404 Value *SVOp1 = SVN->getOperand(1);
5409 for (
int &Elem : Mask) {
5415 if (SVOp0 == Op1 && SVOp1 == Op0) {
5419 if (SVOp0 != Op0 || SVOp1 != Op1)
5425 SmallVector<int> ReconstructMask;
5426 for (
unsigned I = 0;
I <
Mask.size();
I++) {
5429 }
else if (Mask[
I] <
static_cast<int>(NumElts)) {
5430 MaxV1Elt = std::max(MaxV1Elt, Mask[
I]);
5431 auto It =
find_if(
V1, [&](
const std::pair<int, int> &
A) {
5432 return Mask[
I] ==
A.first;
5438 V1.emplace_back(Mask[
I],
V1.size());
5441 MaxV2Elt = std::max<int>(MaxV2Elt, Mask[
I] - NumElts);
5442 auto It =
find_if(V2, [&](
const std::pair<int, int> &
A) {
5443 return Mask[
I] -
static_cast<int>(NumElts) ==
A.first;
5457 sort(ReconstructMask);
5458 OrigReconstructMasks.
push_back(std::move(ReconstructMask));
5465 if (
V1.empty() || V2.
empty() ||
5466 (MaxV1Elt ==
static_cast<int>(
V1.size()) - 1 &&
5467 MaxV2Elt ==
static_cast<int>(V2.
size()) - 1))
5479 if (InputShuffles.contains(SSV))
5481 return SV->getMaskValue(M);
5489 std::pair<int, int>
Y) {
5490 int MXA = GetBaseMaskValue(
A,
X.first);
5491 int MYA = GetBaseMaskValue(
A,
Y.first);
5495 return SortBase(SVI0A,
A,
B);
5497 stable_sort(V2, [&](std::pair<int, int>
A, std::pair<int, int>
B) {
5498 return SortBase(SVI1A,
A,
B);
5503 for (
const auto &Mask : OrigReconstructMasks) {
5504 SmallVector<int> ReconstructMask;
5505 for (
int M : Mask) {
5507 auto It =
find_if(V, [M](
auto A) {
return A.second ==
M; });
5508 assert(It !=
V.end() &&
"Expected all entries in Mask");
5509 return std::distance(
V.begin(), It);
5513 else if (M <
static_cast<int>(NumElts)) {
5516 ReconstructMask.
push_back(NumElts + FindIndex(V2, M));
5519 ReconstructMasks.
push_back(std::move(ReconstructMask));
5524 SmallVector<int> V1A, V1B, V2A, V2B;
5525 for (
unsigned I = 0;
I <
V1.size();
I++) {
5529 for (
unsigned I = 0;
I < V2.
size();
I++) {
5530 V2A.
push_back(GetBaseMaskValue(SVI1A, V2[
I].first));
5531 V2B.
push_back(GetBaseMaskValue(SVI1B, V2[
I].first));
5533 while (V1A.
size() < NumElts) {
5537 while (V2A.
size() < NumElts) {
5549 VT, VT, SV->getShuffleMask(),
CostKind);
5556 unsigned ElementSize = VT->getElementType()->getPrimitiveSizeInBits();
5557 unsigned MaxVectorSize =
5559 unsigned MaxElementsInVector = MaxVectorSize / ElementSize;
5560 if (MaxElementsInVector == 0)
5569 std::set<SmallVector<int, 4>> UniqueShuffles;
5574 unsigned NumFullVectors =
Mask.size() / MaxElementsInVector;
5575 if (NumFullVectors < 2)
5576 return C + ShuffleCost;
5577 SmallVector<int, 4> SubShuffle(MaxElementsInVector);
5578 unsigned NumUniqueGroups = 0;
5579 unsigned NumGroups =
Mask.size() / MaxElementsInVector;
5582 for (
unsigned I = 0;
I < NumFullVectors; ++
I) {
5583 for (
unsigned J = 0; J < MaxElementsInVector; ++J)
5584 SubShuffle[J] = Mask[MaxElementsInVector *
I + J];
5585 if (UniqueShuffles.insert(SubShuffle).second)
5586 NumUniqueGroups += 1;
5588 return C + ShuffleCost * NumUniqueGroups / NumGroups;
5594 SmallVector<int, 16>
Mask;
5595 SV->getShuffleMask(Mask);
5596 return AddShuffleMaskAdjustedCost(
C, Mask);
5599 auto AllShufflesHaveSameOperands =
5600 [](SmallPtrSetImpl<Instruction *> &InputShuffles) {
5601 if (InputShuffles.size() < 2)
5603 ShuffleVectorInst *FirstSV =
5610 std::next(InputShuffles.begin()), InputShuffles.end(),
5611 [&](Instruction *
I) {
5612 ShuffleVectorInst *SV = dyn_cast<ShuffleVectorInst>(I);
5613 return SV && SV->getOperand(0) == In0 && SV->getOperand(1) == In1;
5622 CostBefore += std::accumulate(Shuffles.begin(), Shuffles.end(),
5624 if (AllShufflesHaveSameOperands(InputShuffles)) {
5625 UniqueShuffles.clear();
5626 CostBefore += std::accumulate(InputShuffles.begin(), InputShuffles.end(),
5629 CostBefore += std::accumulate(InputShuffles.begin(), InputShuffles.end(),
5635 FixedVectorType *Op0SmallVT =
5637 FixedVectorType *Op1SmallVT =
5642 UniqueShuffles.clear();
5643 CostAfter += std::accumulate(ReconstructMasks.begin(), ReconstructMasks.end(),
5645 std::set<SmallVector<int>> OutputShuffleMasks({V1A, V1B, V2A, V2B});
5647 std::accumulate(OutputShuffleMasks.begin(), OutputShuffleMasks.end(),
5650 LLVM_DEBUG(
dbgs() <<
"Found a binop select shuffle pattern: " <<
I <<
"\n");
5652 <<
" vs CostAfter: " << CostAfter <<
"\n");
5653 if (CostBefore < CostAfter ||
5664 if (InputShuffles.contains(SSV))
5666 return SV->getOperand(
Op);
5670 GetShuffleOperand(SVI0A, 1), V1A);
5673 GetShuffleOperand(SVI0B, 1), V1B);
5676 GetShuffleOperand(SVI1A, 1), V2A);
5679 GetShuffleOperand(SVI1B, 1), V2B);
5684 I->copyIRFlags(Op0,
true);
5689 I->copyIRFlags(Op1,
true);
5691 for (
int S = 0,
E = ReconstructMasks.size(); S !=
E; S++) {
5694 replaceValue(*Shuffles[S], *NSV,
false);
5697 Worklist.pushValue(NSV0A);
5698 Worklist.pushValue(NSV0B);
5699 Worklist.pushValue(NSV1A);
5700 Worklist.pushValue(NSV1B);
5710bool VectorCombine::shrinkType(Instruction &
I) {
5711 Value *ZExted, *OtherOperand;
5717 Value *ZExtOperand =
I.getOperand(
I.getOperand(0) == OtherOperand ? 1 : 0);
5721 unsigned BW = SmallTy->getElementType()->getPrimitiveSizeInBits();
5723 if (
I.getOpcode() == Instruction::LShr) {
5740 Instruction::ZExt, BigTy, SmallTy,
5741 TargetTransformInfo::CastContextHint::None,
CostKind);
5746 for (User *U : ZExtOperand->
users()) {
5753 ShrinkCost += ZExtCost;
5768 ShrinkCost += ZExtCost;
5775 Instruction::Trunc, SmallTy, BigTy,
5776 TargetTransformInfo::CastContextHint::None,
CostKind);
5781 if (ShrinkCost > CurrentCost)
5785 Value *Op0 = ZExted;
5788 if (
I.getOperand(0) == OtherOperand)
5795 replaceValue(
I, *NewZExtr);
5801bool VectorCombine::foldInsExtVectorToShuffle(Instruction &
I) {
5802 Value *DstVec, *SrcVec;
5803 uint64_t ExtIdx, InsIdx;
5813 if (!DstVecTy || !SrcVecTy ||
5819 if (InsIdx >= NumDstElts || ExtIdx >= NumSrcElts || NumDstElts == 1)
5826 bool NeedExpOrNarrow = NumSrcElts != NumDstElts;
5828 if (NeedDstSrcSwap) {
5830 Mask[InsIdx] = ExtIdx % NumDstElts;
5834 std::iota(
Mask.begin(),
Mask.end(), 0);
5835 Mask[InsIdx] = (ExtIdx % NumDstElts) + NumDstElts;
5848 SmallVector<int> ExtToVecMask;
5849 if (!NeedExpOrNarrow) {
5854 nullptr, {DstVec, SrcVec});
5860 ExtToVecMask[ExtIdx % NumDstElts] = ExtIdx;
5863 DstVecTy, SrcVecTy, ExtToVecMask,
CostKind);
5867 if (!Ext->hasOneUse())
5870 LLVM_DEBUG(
dbgs() <<
"Found a insert/extract shuffle-like pair: " <<
I
5871 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
5874 if (OldCost < NewCost)
5877 if (NeedExpOrNarrow) {
5878 if (!NeedDstSrcSwap)
5891 replaceValue(
I, *Shuf);
5900bool VectorCombine::foldInterleaveIntrinsics(Instruction &
I) {
5901 const APInt *SplatVal0, *SplatVal1;
5911 auto *ExtVTy = VectorType::getExtendedElementVectorType(VTy);
5912 unsigned Width = VTy->getElementType()->getIntegerBitWidth();
5921 LLVM_DEBUG(
dbgs() <<
"VC: The cost to cast from " << *ExtVTy <<
" to "
5922 << *
I.getType() <<
" is too high.\n");
5926 APInt NewSplatVal = SplatVal1->
zext(Width * 2);
5927 NewSplatVal <<= Width;
5928 NewSplatVal |= SplatVal0->
zext(Width * 2);
5930 ExtVTy->getElementCount(), ConstantInt::get(
F.getContext(), NewSplatVal));
5965bool VectorCombine::foldDeinterleaveIntrinsics(Instruction &
I) {
5967 if (
DL->isBigEndian())
5970 using namespace PatternMatch;
5971 Value *DeinterleavedVal;
5982 unsigned HalfElementWidth = ElementWidth / 2;
5986 std::array<ExtractValueInst *, 2> OrigFields{};
5987 for (User *Usr :
I.users()) {
5990 if (!
E ||
E->getNumIndices() != 1)
5992 unsigned Idx = *
E->idx_begin();
5994 if (Idx >= 2 || OrigFields[Idx] || !
E->hasNUses(2))
5996 OrigFields[Idx] =
E;
6000 SmallVector<Instruction *, 2> MergeInsts;
6001 for (
auto *FieldUsr : OrigFields[0]->
users()) {
6009 auto MatchMerge = [&](void) ->
bool {
6012 return match(MergeInsts[0],
6016 match(MergeInsts[1],
6021 if (!MatchMerge()) {
6022 std::swap(MergeInsts[0], MergeInsts[1]);
6037 auto *NewFieldTy = VecTy->getWithNewBitWidth(HalfElementWidth);
6047 if (OldCost <= NewCost || !NewCost.
isValid()) {
6049 dbgs() <<
"VC: New deinterleave2 sequence cost (" << NewCost <<
")"
6050 <<
" is higher than that of the old one (" << OldCost <<
")\n");
6058 Intrinsic::vector_deinterleave2, {NewVecTy}, {NewVecCast});
6059 for (
auto [Idx, MergeInst] :
enumerate(MergeInsts)) {
6061 NewField = Builder.
CreateBitCast(NewField, MergeInst->getType());
6062 replaceValue(*MergeInst, *NewField);
6068bool VectorCombine::foldBitcastOfVPLoad(Instruction &
I) {
6069 const DataLayout &
DL =
I.getDataLayout();
6084 DL.getValueOrABITypeAlignment(
II->getPointerAlignment(), OrigVecTy);
6085 ElementCount OrigVecCnt = OrigVecTy->getElementCount();
6087 ElementCount NewVecCnt = NewVecTy->getElementCount();
6099 II->getMemoryPointerParam(),
false,
6105 {Intrinsic::vp_load, NewVecTy,
II->getMemoryPointerParam(),
false,
6109 <<
" NewCost=" << NewCost <<
"\n");
6110 if (NewCost > OldCost || !NewCost.
isValid())
6117 NewVecTy, Intrinsic::vp_load,
6118 {
II->getMemoryPointerParam(), NewMask, NewEVL});
6121 0, AttrBuilder(
II->getContext()).addAlignmentAttr(OrigAlign));
6122 replaceValue(*Cast, *NewVP);
6130bool VectorCombine::foldBitOrderReverseAndSwap(Instruction &
I) {
6134 Type *Ty =
X->getType();
6135 Type *VecTy =
I.getOperand(0)->getType();
6148 IntrinsicCostAttributes ICABSwap(Intrinsic::bswap, Ty, {Ty});
6149 IntrinsicCostAttributes ICABRev(Intrinsic::bitreverse, Ty, {Ty});
6152 if (!InnerCall->hasOneUse())
6155 else if (!InnerBitCast->hasOneUse())
6158 <<
"\n OldCost: " << OldCost
6159 <<
" vs NewCost: " << NewCost <<
"\n");
6160 if (NewCost.isValid() && NewCost < OldCost) {
6163 Worklist.pushValue(BSwap);
6166 replaceValue(
I, *BRev);
6175 Type *Ty =
I.getType();
6177 TypeSize ElementSize =
DL->getTypeStoreSize(Ty);
6180 Type *NewVecTy = VectorType::get(I8Ty, NewVecCnt);
6193 IntrinsicCostAttributes ICANew(Intrinsic::bitreverse, NewVecTy, {NewVecTy});
6196 InstructionCost NewCost = CastToVecCost + NewIntrinsicCost + CastToOrigCost;
6197 if (!InnerII->hasOneUse())
6200 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
6202 if (!NewCost.
isValid() || NewCost >= OldCost)
6210 replaceValue(
I, *CastToOrig);
6214bool VectorCombine::shrinkLoadForShuffles(Instruction &
I) {
6216 if (!OldLoad || !OldLoad->isSimple())
6223 unsigned const OldNumElements = OldLoadTy->getNumElements();
6229 using IndexRange = std::pair<int, int>;
6230 auto GetIndexRangeInShuffles = [&]() -> std::optional<IndexRange> {
6231 IndexRange OutputRange = IndexRange(OldNumElements, -1);
6232 for (llvm::Use &Use :
I.uses()) {
6234 User *Shuffle =
Use.getUser();
6239 return std::nullopt;
6246 for (
int Index : Mask) {
6247 if (Index >= 0 && Index <
static_cast<int>(OldNumElements)) {
6248 OutputRange.first = std::min(Index, OutputRange.first);
6249 OutputRange.second = std::max(Index, OutputRange.second);
6254 if (OutputRange.second < OutputRange.first)
6255 return std::nullopt;
6261 if (std::optional<IndexRange> Indices = GetIndexRangeInShuffles()) {
6262 unsigned const NewNumElements = Indices->second + 1u;
6266 if (NewNumElements < OldNumElements) {
6271 Type *ElemTy = OldLoadTy->getElementType();
6273 Value *PtrOp = OldLoad->getPointerOperand();
6276 Instruction::Load, OldLoad->getType(), OldLoad->getAlign(),
6277 OldLoad->getPointerAddressSpace(),
CostKind);
6280 OldLoad->getPointerAddressSpace(),
CostKind);
6282 using UseEntry = std::pair<ShuffleVectorInst *, std::vector<int>>;
6284 unsigned const MaxIndex = NewNumElements * 2u;
6286 for (llvm::Use &Use :
I.uses()) {
6293 ArrayRef<int> OldMask = Shuffle->getShuffleMask();
6299 for (
int Index : OldMask) {
6300 if (Index >=
static_cast<int>(MaxIndex))
6314 dbgs() <<
"Found a load used only by shufflevector instructions: "
6315 <<
I <<
"\n OldCost: " << OldCost
6316 <<
" vs NewCost: " << NewCost <<
"\n");
6318 if (OldCost < NewCost || !NewCost.
isValid())
6324 NewLoad->copyMetadata(
I);
6327 for (UseEntry &Use : NewUses) {
6328 ShuffleVectorInst *Shuffle =
Use.first;
6329 std::vector<int> &NewMask =
Use.second;
6336 replaceValue(*Shuffle, *NewShuffle,
false);
6349bool VectorCombine::shrinkPhiOfShuffles(Instruction &
I) {
6351 if (!Phi ||
Phi->getNumIncomingValues() != 2u)
6355 ArrayRef<int> Mask0;
6356 ArrayRef<int> Mask1;
6369 auto const InputNumElements = InputVT->getNumElements();
6371 if (InputNumElements >= ResultVT->getNumElements())
6376 SmallVector<int, 16> NewMask;
6379 for (
auto [
M0,
M1] :
zip(Mask0, Mask1)) {
6380 if (
M0 >= 0 &&
M1 >= 0)
6382 else if (
M0 == -1 &&
M1 == -1)
6395 int MaskOffset = NewMask[0
u];
6396 unsigned Index = (InputNumElements + MaskOffset) % InputNumElements;
6399 for (
unsigned I = 0u;
I < InputNumElements; ++
I) {
6413 <<
"\n OldCost: " << OldCost <<
" vs NewCost: " << NewCost
6416 if (NewCost > OldCost)
6428 auto *NewPhi = Builder.
CreatePHI(NewShuf0->getType(), 2u);
6430 NewPhi->addIncoming(
Op,
Phi->getIncomingBlock(1u));
6436 replaceValue(*Phi, *NewShuf1);
6442bool VectorCombine::run() {
6456 auto Opcode =
I.getOpcode();
6464 if (IsFixedVectorType) {
6466 case Instruction::InsertElement:
6467 if (vectorizeLoadInsert(
I))
6470 case Instruction::ShuffleVector:
6471 if (widenSubvectorLoad(
I))
6482 if (scalarizeOpOrCmp(
I))
6484 if (scalarizeLoad(
I))
6486 if (scalarizeExtExtract(
I))
6488 if (scalarizeVPIntrinsic(
I))
6490 if (foldInterleaveIntrinsics(
I))
6492 if (foldBitcastOfVPLoad(
I))
6496 if (foldDeinterleaveIntrinsics(
I))
6499 if (Opcode == Instruction::Store)
6500 if (foldSingleElementStore(
I))
6504 if (TryEarlyFoldsOnly)
6507 if (Opcode == Instruction::Call)
6508 if (foldBitOrderReverseAndSwap(
I))
6510 if (Opcode == Instruction::BitCast)
6511 if (foldBitOrderReverseAndSwap(
I))
6518 if (IsFixedVectorType) {
6520 case Instruction::InsertElement:
6521 if (foldInsExtFNeg(
I))
6523 if (foldInsExtBinop(
I))
6525 if (foldInsExtVectorToShuffle(
I))
6528 case Instruction::ShuffleVector:
6529 if (foldPermuteOfBinops(
I))
6531 if (foldShuffleOfBinops(
I))
6533 if (foldShuffleOfSelects(
I))
6535 if (foldShuffleOfCastops(
I))
6537 if (foldShuffleOfShuffles(
I))
6539 if (foldPermuteOfIntrinsic(
I))
6541 if (foldShufflesOfLengthChangingShuffles(
I))
6543 if (foldShuffleOfIntrinsics(
I))
6545 if (foldSelectShuffle(
I))
6547 if (foldShuffleToIdentity(
I))
6550 case Instruction::Load:
6551 if (shrinkLoadForShuffles(
I))
6554 case Instruction::BitCast:
6555 if (foldBitcastShuffle(
I))
6557 if (foldSelectsFromBitcast(
I))
6560 case Instruction::And:
6561 case Instruction::Or:
6562 case Instruction::Xor:
6563 if (foldBitOpOfCastops(
I))
6565 if (foldBitOpOfCastConstant(
I))
6568 case Instruction::PHI:
6569 if (shrinkPhiOfShuffles(
I))
6579 case Instruction::Call:
6580 if (foldShuffleFromReductions(
I))
6582 if (foldCastFromReductions(
I))
6585 case Instruction::ExtractElement:
6586 if (foldShuffleChainsToReduce(
I))
6589 case Instruction::ICmp:
6590 if (foldSignBitReductionCmp(
I))
6592 if (foldICmpEqZeroVectorReduce(
I))
6594 if (foldReductionZeroTest(
I))
6596 if (foldEquivalentReductionCmp(
I))
6598 if (foldReduceAddCmpZero(
I))
6601 case Instruction::FCmp:
6602 if (foldExtractExtract(
I))
6605 case Instruction::Or:
6606 if (foldConcatOfBoolMasks(
I))
6611 if (foldExtractExtract(
I))
6613 if (foldExtractedCmps(
I))
6615 if (foldBinopOfReductions(
I))
6624 bool MadeChange =
false;
6625 for (BasicBlock &BB :
F) {
6637 if (!
I->isDebugOrPseudoInst())
6638 MadeChange |= FoldInst(*
I);
6645 while (!Worklist.isEmpty()) {
6655 MadeChange |= FoldInst(*
I);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static cl::opt< unsigned > MaxInstrsToScan("aggressive-instcombine-max-scan-instrs", cl::init(64), cl::Hidden, cl::desc("Max number of instructions to scan for aggressive instcombine."))
This is the interface for LLVM's primary stateless and local alias analysis.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static cl::opt< OutputCostKind > CostKind("cost-kind", cl::desc("Target cost kind"), cl::init(OutputCostKind::RecipThroughput), cl::values(clEnumValN(OutputCostKind::RecipThroughput, "throughput", "Reciprocal throughput"), clEnumValN(OutputCostKind::Latency, "latency", "Instruction latency"), clEnumValN(OutputCostKind::CodeSize, "code-size", "Code size"), clEnumValN(OutputCostKind::SizeAndLatency, "size-latency", "Code size and latency"), clEnumValN(OutputCostKind::All, "all", "Print all cost kinds")))
static cl::opt< IntrinsicCostStrategy > IntrinsicCost("intrinsic-cost-strategy", cl::desc("Costing strategy for intrinsic instructions"), cl::init(IntrinsicCostStrategy::InstructionCost), cl::values(clEnumValN(IntrinsicCostStrategy::InstructionCost, "instruction-cost", "Use TargetTransformInfo::getInstructionCost"), clEnumValN(IntrinsicCostStrategy::IntrinsicCost, "intrinsic-cost", "Use TargetTransformInfo::getIntrinsicInstrCost"), clEnumValN(IntrinsicCostStrategy::TypeBasedIntrinsicCost, "type-based-intrinsic-cost", "Calculate the intrinsic cost based only on argument types")))
This file defines the DenseMap class.
This is the interface for a simple mod/ref and alias analysis over globals.
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
static void eraseInstruction(Instruction &I, ICFLoopSafetyInfo &SafetyInfo, MemorySSAUpdater &MSSAU)
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
const SmallVectorImpl< MachineOperand > & Cond
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static SymbolRef::Type getType(const Symbol *Sym)
static bool isFreeConcat(ArrayRef< InstLane > Item, TTI::TargetCostKind CostKind, const TargetTransformInfo &TTI)
Detect concat of multiple values into a vector.
static void analyzeCostOfVecReduction(const IntrinsicInst &II, TTI::TargetCostKind CostKind, const TargetTransformInfo &TTI, InstructionCost &CostBeforeReduction, InstructionCost &CostAfterReduction)
static 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 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
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.
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
const APInt & smin(const APInt &A, const APInt &B)
Determine the smaller of two APInts considered to be signed.
const APInt & smax(const APInt &A, const APInt &B)
Determine the larger of two APInts considered to be signed.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
LLVM_ABI AttributeSet getFnAttributes(LLVMContext &C, ID id)
Return the function attributes for an intrinsic.
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
match_combine_and< Ty... > m_CombineAnd(const Ty &...Ps)
Combine pattern matchers matching all of Ps patterns.
cst_pred_ty< is_all_ones > m_AllOnes()
Match an integer or vector with all bits set.
BinaryOp_match< LHS, RHS, Instruction::And > m_And(const LHS &L, const RHS &R)
auto m_BSwap(const Opnd0 &Op0)
auto m_Cmp()
Matches any compare instruction and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Add > m_Add(const LHS &L, const RHS &R)
auto m_BitReverse(const Opnd0 &Op0)
BinaryOp_match< LHS, RHS, Instruction::URem > m_URem(const LHS &L, const RHS &R)
auto m_Poison()
Match an arbitrary poison constant.
ap_match< APInt > m_APInt(const APInt *&Res)
Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.
CastInst_match< OpTy, TruncInst > m_Trunc(const OpTy &Op)
Matches Trunc.
specific_intval< false > m_SpecificInt(const APInt &V)
Match a specific integer value or vector with all elements equal to the value.
bool match(Val *V, const Pattern &P)
match_bind< Instruction > m_Instruction(Instruction *&I)
Match an instruction, capturing it if we match.
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
DisjointOr_match< LHS, RHS > m_DisjointOr(const LHS &L, const RHS &R)
BinOpPred_match< LHS, RHS, is_right_shift_op > m_Shr(const LHS &L, const RHS &R)
Matches logical shift operations.
CmpClass_match< LHS, RHS, ICmpInst, true > m_c_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
Matches an ICmp with a predicate over LHS and RHS in either order.
TwoOps_match< Val_t, Idx_t, Instruction::ExtractElement > m_ExtractElt(const Val_t &Val, const Idx_t &Idx)
Matches ExtractElementInst.
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
auto m_BinOp()
Match an arbitrary binary operation and ignore it.
auto m_Value()
Match an arbitrary value and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
auto m_Constant()
Match an arbitrary Constant and ignore it.
TwoOps_match< V1_t, V2_t, Instruction::ShuffleVector > m_Shuffle(const V1_t &v1, const V2_t &v2)
Matches ShuffleVectorInst independently of mask value.
cst_pred_ty< is_non_zero_int > m_NonZeroInt()
Match a non-zero integer or a vector with all non-zero elements.
OneOps_match< OpTy, Instruction::Load > m_Load(const OpTy &Op)
Matches LoadInst.
CastInst_match< OpTy, ZExtInst > m_ZExt(const OpTy &Op)
Matches ZExt.
OverflowingBinaryOp_match< LHS, RHS, Instruction::Shl, OverflowingBinaryOperator::NoUnsignedWrap > m_NUWShl(const LHS &L, const RHS &R)
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
OverflowingBinaryOp_match< LHS, RHS, Instruction::Mul, OverflowingBinaryOperator::NoUnsignedWrap > m_NUWMul(const LHS &L, const RHS &R)
BinOpPred_match< LHS, RHS, is_bitwiselogic_op, true > m_c_BitwiseLogic(const LHS &L, const RHS &R)
Matches bitwise logic operations in either order.
CastOperator_match< OpTy, Instruction::BitCast > m_BitCast(const OpTy &Op)
Matches BitCast.
match_combine_or< CastInst_match< OpTy, SExtInst >, NNegZExt_match< OpTy > > m_SExtLike(const OpTy &Op)
Match either "sext" or "zext nneg".
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
auto m_Deinterleave2(const Opnd &Op)
BinaryOp_match< LHS, RHS, Instruction::LShr > m_LShr(const LHS &L, const RHS &R)
CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
match_combine_or< CastInst_match< OpTy, ZExtInst >, CastInst_match< OpTy, SExtInst > > m_ZExtOrSExt(const OpTy &Op)
FNeg_match< OpTy > m_FNeg(const OpTy &X)
Match 'fneg X' as 'fsub -0.0, X'.
BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)
auto m_Undef()
Match an arbitrary undef constant.
CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)
Matches SExt.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
BinaryOp_match< LHS, RHS, Instruction::Or, true > m_c_Or(const LHS &L, const RHS &R)
Matches an Or with LHS and RHS in either order.
ThreeOps_match< Val_t, Elt_t, Idx_t, Instruction::InsertElement > m_InsertElt(const Val_t &Val, const Elt_t &Elt, const Idx_t &Idx)
Matches InsertElementInst.
auto m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
@ Valid
The data is already valid.
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
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.
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