83#ifdef EXPENSIVE_CHECKS
118using namespace std::placeholders;
120#define SV_NAME "slp-vectorizer"
121#define DEBUG_TYPE "SLP"
123STATISTIC(NumVectorInstructions,
"Number of vector instructions generated");
124STATISTIC(NumStridedStoreChains,
"Number of vectorized stride stores");
125STATISTIC(NumStoreChains,
"Number of vector stores created");
126STATISTIC(NumVectorizedStores,
"Number of vectorized stores");
129 "Controls which SLP graphs should be vectorized.");
133 cl::desc(
"Run the SLP vectorization passes"));
137 cl::desc(
"Enable vectorization for wider vector utilization"));
141 cl::desc(
"Only vectorize if you gain more than this "
146 cl::desc(
"Attempt to vectorize horizontal reductions"));
151 "Attempt to vectorize horizontal reductions feeding into a store"));
155 cl::desc(
"Improve the code quality by splitting alternate instructions"));
159 cl::desc(
"Reject vectorization if vector instruction count exceeds "
160 "scalar instruction count"));
164 cl::desc(
"Attempt to vectorize for this register size in bits"));
168 cl::desc(
"Maximum SLP vectorization factor (0=unlimited)"));
176 cl::desc(
"Limit the size of the SLP scheduling region per block"));
180 cl::desc(
"Attempt to vectorize for this register size in bits"));
184 cl::desc(
"Limit the recursion depth when building a vectorizable tree"));
188 cl::desc(
"Only vectorize small trees if they are fully vectorizable"));
192 cl::desc(
"Do not vectorize a bundle of PHI nodes if the product of the "
193 "bundle size and the number of incoming values exceeds this "
194 "value, to limit the compile time spent on wide PHIs"));
200 cl::desc(
"The maximum look-ahead depth for operand reordering scores"));
209 cl::desc(
"The maximum look-ahead depth for searching best rooting option"));
213 cl::desc(
"The minimum number of loads, which should be considered strided, "
214 "if the stride is > 1 or is runtime value"));
219 "The minimum number of stores, which should be considered strided, "
220 "if the stride is > 1 or is runtime value"));
224 cl::desc(
"The maximum stride, considered to be profitable."));
229 cl::desc(
"Enable SLP trees to be built from strided "
234 cl::desc(
"Enable vectorization of non-consecutive stores as a single "
235 "masked store, when the target supports masked stores."));
239 cl::desc(
"Disable tree reordering even if it is "
240 "profitable. Used for testing only."));
244 cl::desc(
"Generate strided loads even if they are not "
245 "profitable. Used for testing only."));
249 cl::desc(
"Display the SLP trees with Graphviz"));
253 cl::desc(
"Try to vectorize with non-power-of-2 number of elements."));
257 cl::desc(
"Force vectorization of non-vectorizable stores operands."));
262 "Use non-vectorizable instructions as potential reduction roots."));
266 cl::desc(
"Use poor-throughput instructions (e.g. fdiv, frem, fsqrt) as "
267 "standalone vectorization seeds."));
271 cl::desc(
"Use instructions with the single user as standalone "
272 "vectorization seeds."));
284 cl::desc(
"Try to replace values with the idempotent instructions for "
285 "better vectorization."));
290 cl::desc(
"Gather operands of associative binary chains into one node."));
297 cl::desc(
"Max flattened operand columns for which associative-chain "
298 "reordering runs the full operand reorder."));
302 cl::desc(
"Loop trip count, considered by the cost model during "
303 "modeling (0=loops are ignored and considered flat code)"));
314 cl::desc(
"Use per-lane execution scale for gather/buildvector tree "
315 "entries to model LICM-hoistable buildvector sequences."));
320 cl::desc(
"Allow SLP to version a block with runtime alias checks to "
321 "vectorize trees blocked by may-alias memory dependencies."));
327 cl::desc(
"The maximum number of runtime alias checks generated to guard a "
328 "single SLP-vectorized region."));
333 "slp-runtime-alias-checks-max-scalar-cost-percent",
cl::init(25),
335 cl::desc(
"Maximum SLP runtime alias check cost, as a percentage of the "
336 "guarded scalar region cost, before versioning is rejected to "
337 "avoid pessimizing the scalar fallback path."));
377static std::optional<TargetTransformInfo::ShuffleKind>
390 return std::max(S, VTy->getNumElements());
393 Value *Vec1 =
nullptr;
394 Value *Vec2 =
nullptr;
399 Value *Vec = EE->getVectorOperand();
405 ShuffleMode CommonShuffleMode =
Unknown;
407 for (
unsigned I = 0,
E = VL.
size();
I <
E; ++
I) {
417 auto *Vec = EI->getVectorOperand();
431 if (Idx->getValue().uge(
Size))
433 unsigned IntIdx = Idx->getValue().getZExtValue();
440 if (!Vec1 || Vec1 == Vec) {
442 }
else if (!Vec2 || Vec2 == Vec) {
448 if (CommonShuffleMode == Permute)
452 if (Mask[
I] %
Size !=
I) {
453 CommonShuffleMode = Permute;
456 CommonShuffleMode =
Select;
459 if (CommonShuffleMode ==
Select && Vec2)
472 const unsigned Limit = std::numeric_limits<unsigned>::max()) {
475 unsigned NumParts =
TTI.getNumberOfParts(VecTy);
476 if (NumParts == 0 || NumParts >= Limit)
482 if (NumParts >= Sz || PWSz % NumParts != 0 ||
483 (PWSz / NumParts) % ScalarSz != 0 ||
486 const unsigned NumElts = PWSz / NumParts;
495 class ScheduleEntity;
497 class ScheduleCopyableData;
498 class ScheduleBundle;
536 : BatchAA(*Aa), F(Func), SE(Se), TTI(Tti), TLI(TLi), LI(Li), DT(Dt),
556 MinVecRegSize = TTI->getMinVectorRegisterBitWidth();
569 ArrayRef<std::tuple<WeakTrackingVH, unsigned, bool, bool>>
570 VectorValuesAndScales = {});
594 const SmallDenseSet<Value *> &UserIgnoreLst);
602 NarrowedChainInsts.insert(Insts.
begin(), Insts.
end());
609 return HasRuntimeCheckableBlockers;
616 HasRuntimeCheckableBlockers = V;
639 HasRuntimeCheckableBlockers =
false;
640 HasNonCheckableMemBlocker =
false;
641 RTChecksFinalized =
false;
643 RTOrigBodyOrder.clear();
664 return ScalarFallbackBlocks.contains(BB);
670 return FailedRuntimeChecksBlocks.contains(BB);
676 FailedRuntimeChecksBlocks.insert(BB);
692 assert(!VectorizableTree.empty() &&
"No graph to get the first node from");
693 return *VectorizableTree.front();
697 assert(!VectorizableTree.empty() &&
"No graph to get the first node from");
698 return *VectorizableTree.front();
713 if (Root.State != TreeEntry::Vectorize || Root.isAltShuffle() ||
714 !Root.Scalars.
front()->getType()->isIntegerTy())
716 auto It = MinBWs.find(&Root);
717 if (It != MinBWs.end())
721 if (Root.getOpcode() == Instruction::ZExt ||
722 Root.getOpcode() == Instruction::SExt)
723 return std::make_pair(
cast<CastInst>(Root.getMainOp())->getSrcTy(),
724 Root.getOpcode() == Instruction::SExt);
736 if (ReductionBitWidth == 0 ||
752 (
getRootNode().CombinedOp == TreeEntry::ReducedBitcast ||
753 getRootNode().CombinedOp == TreeEntry::ReducedBitcastBSwap ||
754 getRootNode().CombinedOp == TreeEntry::ReducedBitcastLoads ||
755 getRootNode().CombinedOp == TreeEntry::ReducedBitcastBSwapLoads) &&
762 getRootNode().CombinedOp == TreeEntry::ReducedCmpBitcast &&
781 VectorizableTree.clear();
782 ScalarToTreeEntries.clear();
783 DeletedNodes.clear();
784 TransformedToGatherNodes.clear();
785 OperandsToTreeEntry.clear();
786 ScalarsInSplitNodes.clear();
788 ReassocScalarToTreeEntries.clear();
789 KeptReassocScalars.clear();
790 NonScheduledFirst.clear();
791 EntryToLastInstruction.clear();
792 LastInstructionToPos.clear();
793 LoadEntriesToVectorize.clear();
794 IsGraphTransformMode =
false;
795 GatheredLoadsEntriesFirst.reset();
796 SplatGatheredScalarsRoots.clear();
797 CompressEntryToData.clear();
798 ExternalUses.clear();
799 ExternalUsesAsOriginalScalar.clear();
800 ExternalUsesWithNonUsers.clear();
801 ExternalUseReplacements.clear();
803 HasRuntimeCheckableBlockers =
false;
804 HasNonCheckableMemBlocker =
false;
805 RTChecksFinalized =
false;
806 for (
auto &Iter : BlocksSchedules) {
807 BlockScheduling *BS = Iter.second.get();
811 ReductionBitWidth = 0;
813 CastMaxMinBWSizes.reset();
814 ExtraBitWidthNodes.clear();
815 InstrElementSize.clear();
816 UserIgnoreList =
nullptr;
817 NarrowedChainInsts.clear();
818 PostponedGathers.clear();
819 ValueToGatherNodes.clear();
820 TreeEntryToStridedPtrInfoMap.clear();
821 CurrentLoopNest.clear();
822 MergedLoopBTCs.clear();
838 assert(!Order.
empty() &&
"expected non-empty order");
839 const unsigned Sz = Order.
size();
841 return P.value() ==
P.index() ||
P.value() == Sz;
867 std::optional<OrdersType>
909 return MaxVecRegSize;
914 return MinVecRegSize;
922 unsigned Limit = std::numeric_limits<unsigned>::max())
const {
923 auto [It, Inserted] =
924 NumberOfPartsCache.try_emplace(std::make_tuple(VecTy, ScalarTy, Limit));
936 MaxVFOption : TTI->getMaximumVF(ElemWidth, Opcode);
937 return MaxVF ? MaxVF : UINT_MAX;
970 Align Alignment,
const int64_t Diff,
971 const size_t Sz)
const;
1011 Value *Ptr0, StridedPtrInfo &SPtrInfo)
const;
1030 Align CommonAlignment,
1032 StridedPtrInfo &SPtrInfo,
bool IsLoad)
const;
1047 StridedPtrInfo &SPtrInfo,
1048 unsigned *BestVF =
nullptr,
1049 bool TryRecursiveCheck =
true)
const;
1055 auto IsSame = [&](
const TreeEntry *TE) {
return TE->isSame(VL); };
1069 for (
Value *V : VL) {
1073 for (
const TreeEntry *TE : ValueToGatherNodes.lookup(V)) {
1074 if (!Visited.
insert(TE).second)
1085 ListOfKnonwnNonVectorizableLoads.insert(
hash_value(VL));
1089 template <
typename T>
1091 return ListOfKnonwnNonVectorizableLoads.contains(
hash_value(VL));
1116 OS <<
"{User:" << (
UserTE ? std::to_string(
UserTE->Idx) :
"null")
1117 <<
" EdgeIdx:" <<
EdgeIdx <<
"}";
1142 : TLI(TLI), DL(DL), SE(SE), R(R), NumLanes(NumLanes),
1143 MaxLevel(MaxLevel) {}
1201 auto AllUsersAreInternal = [U1, U2,
this](
Value *
V1,
Value *V2) {
1206 auto AllUsersVectorized = [U1, U2,
this](
Value *V) {
1208 return U == U1 || U == U2 || R.isVectorized(U);
1211 return AllUsersVectorized(
V1) && AllUsersVectorized(V2);
1214 if (R.TTI->isLegalBroadcastLoad(
V1->getType(),
1216 ((
int)
V1->getNumUses() == NumLanes ||
1217 AllUsersAreInternal(
V1, V2)))
1227 auto CheckSameEntryOrFail = [&]() {
1232 any_of(TEs2, [&](TreeEntry *E) {
return Set.contains(E); }))
1241 if (LI1->getParent() != LI2->getParent() || !LI1->isSimple() ||
1243 return CheckSameEntryOrFail();
1246 LI1->getType(), LI1->getPointerOperand(), LI2->getType(),
1247 LI2->getPointerOperand(), DL, SE,
true);
1248 if (!Dist || *Dist == 0) {
1251 R.TTI->isLegalMaskedGather(
1254 return CheckSameEntryOrFail();
1258 if (std::abs(*Dist) > NumLanes / 2)
1291 Value *EV2 =
nullptr;
1304 int Dist = Idx2 - Idx1;
1307 if (std::abs(Dist) == 0)
1309 if (std::abs(Dist) > NumLanes / 2)
1316 return CheckSameEntryOrFail();
1322 if (I1->getParent() != I2->getParent())
1323 return CheckSameEntryOrFail();
1332 V->getType() ==
Cond->getType()) ||
1335 V->getType() ==
Cond->getType()))
1361 return CheckSameEntryOrFail();
1395 int ShallowScoreAtThisLevel =
1406 if (CurrLevel == MaxLevel || !(I1 && I2) || I1 == I2 ||
1409 (I1->getNumOperands() > 2 && I2->getNumOperands() > 2) ||
1411 ShallowScoreAtThisLevel))
1412 return ShallowScoreAtThisLevel;
1413 assert(I1 && I2 &&
"Should have early exited.");
1420 if (I1->getNumOperands() != I2->getNumOperands())
1422 for (
unsigned OpIdx1 = 0, NumOperands1 = I1->getNumOperands();
1423 OpIdx1 != NumOperands1; ++OpIdx1) {
1425 int MaxTmpScore = 0;
1426 unsigned MaxOpIdx2 = 0;
1427 bool FoundBest =
false;
1431 ? I2->getNumOperands()
1432 : std::min(I2->getNumOperands(), OpIdx1 + 1);
1433 assert(FromIdx <= ToIdx &&
"Bad index");
1434 for (
unsigned OpIdx2 = FromIdx; OpIdx2 != ToIdx; ++OpIdx2) {
1436 if (Op2Used.
count(OpIdx2))
1441 I1, I2, CurrLevel + 1, {});
1444 TmpScore > MaxTmpScore) {
1445 MaxTmpScore = TmpScore;
1452 Op2Used.
insert(MaxOpIdx2);
1453 ShallowScoreAtThisLevel += MaxTmpScore;
1456 return ShallowScoreAtThisLevel;
1487 struct OperandData {
1488 OperandData() =
default;
1489 OperandData(
Value *V,
bool APO,
bool IsUsed)
1490 : V(V), APO(APO), IsUsed(IsUsed) {}
1500 bool IsUsed =
false;
1509 enum class ReorderingMode {
1523 unsigned ArgSize = 0;
1529 const Loop *L =
nullptr;
1532 OperandData &getData(
unsigned OpIdx,
unsigned Lane) {
1533 return OpsVec[OpIdx][Lane];
1537 const OperandData &getData(
unsigned OpIdx,
unsigned Lane)
const {
1538 return OpsVec[OpIdx][Lane];
1543 for (
unsigned OpIdx = 0, NumOperands = getNumOperands();
1544 OpIdx != NumOperands; ++OpIdx)
1545 for (
unsigned Lane = 0, NumLanes = getNumLanes(); Lane != NumLanes;
1547 OpsVec[OpIdx][Lane].IsUsed =
false;
1551 void swap(
unsigned OpIdx1,
unsigned OpIdx2,
unsigned Lane) {
1552 std::swap(OpsVec[OpIdx1][Lane], OpsVec[OpIdx2][Lane]);
1564 int getSplatScore(
unsigned Lane,
unsigned OpIdx,
unsigned Idx,
1566 Value *IdxLaneV = getData(Idx, Lane).V;
1574 Value *OpIdxLnV = getData(OpIdx, Ln).V;
1579 unsigned UniquesCount = Uniques.
size();
1580 auto IdxIt = Uniques.
find(IdxLaneV);
1581 unsigned UniquesCntWithIdxLaneV =
1582 IdxIt != Uniques.
end() ? UniquesCount : UniquesCount + 1;
1583 Value *OpIdxLaneV = getData(OpIdx, Lane).V;
1584 auto OpIdxIt = Uniques.
find(OpIdxLaneV);
1585 unsigned UniquesCntWithOpIdxLaneV =
1586 OpIdxIt != Uniques.
end() ? UniquesCount : UniquesCount + 1;
1587 if (UniquesCntWithIdxLaneV == UniquesCntWithOpIdxLaneV)
1589 return std::min(
bit_ceil(UniquesCntWithOpIdxLaneV) -
1590 UniquesCntWithOpIdxLaneV,
1591 UniquesCntWithOpIdxLaneV -
1593 ((IdxIt != Uniques.
end() && UsedLanes.
test(IdxIt->second))
1594 ? UniquesCntWithIdxLaneV -
bit_floor(UniquesCntWithIdxLaneV)
1595 :
bit_ceil(UniquesCntWithIdxLaneV) - UniquesCntWithIdxLaneV);
1604 int getExternalUseScore(
unsigned Lane,
unsigned OpIdx,
unsigned Idx)
const {
1605 Value *IdxLaneV = getData(Idx, Lane).V;
1606 Value *OpIdxLaneV = getData(OpIdx, Lane).V;
1618 return R.areAllUsersVectorized(IdxLaneI)
1626 static constexpr int ScoreScaleFactor = 10;
1628 static constexpr int ScoreConstantScaleFactor = 6;
1636 int Lane,
unsigned OpIdx,
unsigned Idx,
1647 getSplatScore(Lane, OpIdx, Idx, UsedLanes) * ScoreScaleFactor;
1648 if (Score <= -SplatScore) {
1652 Score += SplatScore;
1658 const int SF = (LHS == RHS &&
isConstant(LHS))
1659 ? ScoreConstantScaleFactor
1662 Score += getExternalUseScore(Lane, OpIdx, Idx);
1680 std::optional<unsigned>
1681 getBestOperand(
unsigned OpIdx,
int Lane,
int LastLane,
1685 unsigned NumOperands = getNumOperands();
1688 Value *OpLastLane = getData(OpIdx, LastLane).V;
1691 ReorderingMode RMode = ReorderingModes[OpIdx];
1692 if (RMode == ReorderingMode::Failed)
1693 return std::nullopt;
1696 bool OpIdxAPO = getData(OpIdx, Lane).APO;
1702 std::optional<unsigned> Idx;
1706 BestScoresPerLanes.try_emplace(std::make_pair(OpIdx, Lane), 0)
1712 bool IsUsed = RMode == ReorderingMode::Splat ||
1713 RMode == ReorderingMode::Constant ||
1714 RMode == ReorderingMode::Load;
1716 for (
unsigned Idx = 0; Idx != NumOperands; ++Idx) {
1718 OperandData &OpData = getData(Idx, Lane);
1720 bool OpAPO = OpData.APO;
1729 if (OpAPO != OpIdxAPO)
1734 case ReorderingMode::Load:
1735 case ReorderingMode::Opcode: {
1736 bool LeftToRight = Lane > LastLane;
1737 Value *OpLeft = (LeftToRight) ? OpLastLane :
Op;
1738 Value *OpRight = (LeftToRight) ?
Op : OpLastLane;
1739 int Score = getLookAheadScore(OpLeft, OpRight, MainAltOps, Lane,
1740 OpIdx, Idx, IsUsed, UsedLanes);
1741 if (Score >
static_cast<int>(BestOp.Score) ||
1742 (Score > 0 && Score ==
static_cast<int>(BestOp.Score) &&
1745 BestOp.Score = Score;
1746 BestScoresPerLanes[std::make_pair(OpIdx, Lane)] = Score;
1750 case ReorderingMode::Constant:
1752 (!BestOp.Score && L && L->isLoopInvariant(
Op))) {
1756 BestScoresPerLanes[std::make_pair(OpIdx, Lane)] =
1763 case ReorderingMode::Splat:
1765 IsUsed =
Op == OpLastLane;
1766 if (
Op == OpLastLane) {
1768 BestScoresPerLanes[std::make_pair(OpIdx, Lane)] =
1774 case ReorderingMode::Failed:
1780 getData(*BestOp.Idx, Lane).IsUsed = IsUsed;
1784 return std::nullopt;
1791 unsigned getBestLaneToStartReordering()
const {
1792 unsigned Min = UINT_MAX;
1793 unsigned SameOpNumber = 0;
1804 for (
int I = getNumLanes();
I > 0; --
I) {
1805 unsigned Lane =
I - 1;
1806 OperandsOrderData NumFreeOpsHash =
1807 getMaxNumOperandsThatCanBeReordered(Lane);
1810 if (NumFreeOpsHash.NumOfAPOs < Min) {
1811 Min = NumFreeOpsHash.NumOfAPOs;
1812 SameOpNumber = NumFreeOpsHash.NumOpsWithSameOpcodeParent;
1814 HashMap[NumFreeOpsHash.Hash] = std::make_pair(1, Lane);
1815 }
else if (NumFreeOpsHash.NumOfAPOs == Min &&
1816 NumFreeOpsHash.NumOpsWithSameOpcodeParent < SameOpNumber) {
1819 SameOpNumber = NumFreeOpsHash.NumOpsWithSameOpcodeParent;
1820 HashMap[NumFreeOpsHash.Hash] = std::make_pair(1, Lane);
1821 }
else if (NumFreeOpsHash.NumOfAPOs == Min &&
1822 NumFreeOpsHash.NumOpsWithSameOpcodeParent == SameOpNumber) {
1823 auto [It, Inserted] =
1824 HashMap.
try_emplace(NumFreeOpsHash.Hash, 1, Lane);
1830 unsigned BestLane = 0;
1831 unsigned CntMin = UINT_MAX;
1833 if (
Data.second.first < CntMin) {
1834 CntMin =
Data.second.first;
1835 BestLane =
Data.second.second;
1842 struct OperandsOrderData {
1845 unsigned NumOfAPOs = UINT_MAX;
1848 unsigned NumOpsWithSameOpcodeParent = 0;
1862 OperandsOrderData getMaxNumOperandsThatCanBeReordered(
unsigned Lane)
const {
1863 unsigned CntTrue = 0;
1864 unsigned NumOperands = getNumOperands();
1874 bool AllUndefs =
true;
1875 unsigned NumOpsWithSameOpcodeParent = 0;
1879 for (
unsigned OpIdx = 0; OpIdx != NumOperands; ++OpIdx) {
1880 const OperandData &OpData = getData(OpIdx, Lane);
1887 I->getParent() != Parent) {
1888 if (NumOpsWithSameOpcodeParent == 0) {
1889 NumOpsWithSameOpcodeParent = 1;
1891 Parent =
I->getParent();
1893 --NumOpsWithSameOpcodeParent;
1896 ++NumOpsWithSameOpcodeParent;
1905 OperandsOrderData
Data;
1906 Data.NumOfAPOs = std::max(CntTrue, NumOperands - CntTrue);
1907 Data.NumOpsWithSameOpcodeParent = NumOpsWithSameOpcodeParent;
1918 return VL.
size() == getNumLanes();
1920 "Expected same number of lanes");
1921 assert(S.
valid() &&
"InstructionsState is invalid.");
1926 OpsVec.resize(ArgSize);
1927 unsigned NumLanes = VL.
size();
1928 for (OperandDataVec &
Ops : OpsVec)
1929 Ops.resize(NumLanes);
1944 OpsVec[OpIdx][Lane] = {
Operands[OpIdx][Lane],
true,
false};
1947 bool IsInverseOperation =
false;
1950 IsInverseOperation =
1953 assert(
I &&
"Expected instruction");
1961 bool APO = (OpIdx == 0) ?
false : IsInverseOperation;
1962 OpsVec[OpIdx][Lane] = {
Operands[OpIdx][Lane], APO,
false};
1968 unsigned getNumOperands()
const {
return ArgSize; }
1971 unsigned getNumLanes()
const {
return OpsVec[0].size(); }
1974 Value *getValue(
unsigned OpIdx,
unsigned Lane)
const {
1975 return getData(OpIdx, Lane).V;
1979 bool empty()
const {
return OpsVec.empty(); }
1982 void clear() { OpsVec.clear(); }
1987 bool shouldBroadcast(
Value *
Op,
unsigned OpIdx,
unsigned Lane) {
1988 assert(
Op == getValue(OpIdx, Lane) &&
1989 "Op is expected to be getValue(OpIdx, Lane).");
1993 bool OpAPO = getData(OpIdx, Lane).APO;
1994 bool IsInvariant = L && L->isLoopInvariant(
Op);
1996 for (
unsigned Ln = 0, Lns = getNumLanes(); Ln != Lns; ++Ln) {
2000 bool FoundCandidate =
false;
2001 for (
unsigned OpI = 0, OpE = getNumOperands(); OpI != OpE; ++OpI) {
2002 OperandData &
Data = getData(OpI, Ln);
2003 if (
Data.APO != OpAPO ||
Data.IsUsed)
2005 Value *OpILane = getValue(OpI, Lane);
2029 L->isLoopInvariant(
Data.V))) {
2030 FoundCandidate =
true;
2037 if (!FoundCandidate)
2040 return getNumLanes() == 2 || Cnt > 1;
2045 bool canBeVectorized(
Instruction *
Op,
unsigned OpIdx,
unsigned Lane)
const {
2046 assert(
Op == getValue(OpIdx, Lane) &&
2047 "Op is expected to be getValue(OpIdx, Lane).");
2048 bool OpAPO = getData(OpIdx, Lane).APO;
2049 for (
unsigned Ln = 0, Lns = getNumLanes(); Ln != Lns; ++Ln) {
2053 const OperandData &
Data = getData(OpI, Ln);
2054 if (
Data.APO != OpAPO ||
Data.IsUsed)
2056 Value *OpILn = getValue(OpI, Ln);
2057 return (L && L->isLoopInvariant(OpILn)) ||
2070 : TLI(*R.TLI), DL(*R.DL), SE(*R.SE), R(R),
2071 L(R.LI->getLoopFor(S.getMainOp()->
getParent())) {
2073 appendOperands(RootVL,
Operands, S);
2080 : TLI(*R.TLI), DL(*R.DL), SE(*R.SE), R(R), L(R.LI->getLoopFor(BB)) {
2081 assert(!
Operands.empty() &&
"Expected at least one operand column");
2083 OpsVec.resize(ArgSize);
2084 unsigned NumLanes =
Operands.front().size();
2086 Ops.resize(NumLanes);
2088 Ops[Lane] = OperandData(
Operands[OpIdx][Lane],
false,
2097 assert(OpsVec[OpIdx].
size() == getNumLanes() &&
2098 "Expected same num of lanes across all operands");
2099 for (
unsigned Lane = 0, Lanes = getNumLanes(); Lane != Lanes; ++Lane)
2100 OpVL[Lane] = OpsVec[OpIdx][Lane].V;
2108 unsigned NumOperands = getNumOperands();
2109 unsigned NumLanes = getNumLanes();
2129 unsigned FirstLane = getBestLaneToStartReordering();
2132 for (
unsigned OpIdx = 0; OpIdx != NumOperands; ++OpIdx) {
2133 Value *OpLane0 = getValue(OpIdx, FirstLane);
2138 if (shouldBroadcast(OpLane0, OpIdx, FirstLane) ||
2139 !canBeVectorized(OpILane0, OpIdx, FirstLane))
2140 ReorderingModes[OpIdx] = ReorderingMode::Splat;
2142 ReorderingModes[OpIdx] = ReorderingMode::Load;
2144 ReorderingModes[OpIdx] = ReorderingMode::Opcode;
2146 ReorderingModes[OpIdx] = ReorderingMode::Constant;
2149 ReorderingModes[OpIdx] = ReorderingMode::Splat;
2158 auto &&SkipReordering = [
this]() {
2161 for (
const OperandData &
Data : Op0)
2164 ArrayRef(OpsVec).slice(1, getNumOperands() - 1)) {
2165 if (
any_of(
Op, [&UniqueValues](
const OperandData &
Data) {
2170 return UniqueValues.
size() != 2;
2182 if (SkipReordering())
2185 bool StrategyFailed =
false;
2193 for (
unsigned I = 0;
I < NumOperands; ++
I)
2194 MainAltOps[
I].push_back(getData(
I, FirstLane).V);
2197 UsedLanes.
set(FirstLane);
2198 for (
unsigned Distance = 1; Distance != NumLanes; ++Distance) {
2200 for (
int Direction : {+1, -1}) {
2201 int Lane = FirstLane + Direction * Distance;
2202 if (Lane < 0 || Lane >= (
int)NumLanes)
2204 UsedLanes.
set(Lane);
2205 int LastLane = Lane - Direction;
2206 assert(LastLane >= 0 && LastLane < (
int)NumLanes &&
2209 for (
unsigned OpIdx = 0; OpIdx != NumOperands; ++OpIdx) {
2211 std::optional<unsigned> BestIdx =
2212 getBestOperand(OpIdx, Lane, LastLane, ReorderingModes,
2213 MainAltOps[OpIdx], UsedLanes);
2220 swap(OpIdx, *BestIdx, Lane);
2223 StrategyFailed =
true;
2226 if (MainAltOps[OpIdx].
size() != 2) {
2227 OperandData &AltOp = getData(OpIdx, Lane);
2237 if (!StrategyFailed)
2242#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2245 case ReorderingMode::Load:
2247 case ReorderingMode::Opcode:
2249 case ReorderingMode::Constant:
2251 case ReorderingMode::Splat:
2253 case ReorderingMode::Failed:
2274 const unsigned Indent = 2;
2276 for (
const OperandDataVec &OpDataVec : OpsVec) {
2277 OS <<
"Operand " << Cnt++ <<
"\n";
2278 for (
const OperandData &OpData : OpDataVec) {
2279 OS.
indent(Indent) <<
"{";
2280 if (
Value *V = OpData.V)
2284 OS <<
", APO:" << OpData.APO <<
"}\n";
2301 std::pair<std::optional<int>,
int>
2306 int BestScore = Limit;
2307 std::optional<int> Index;
2308 for (
int I :
seq<int>(0, Candidates.size())) {
2310 Candidates[
I].second,
2313 if (Score > BestScore) {
2318 return std::make_pair(Index, BestScore);
2331 DeletedInstructions.insert(
I);
2336 template <
typename T>
2339 ArrayRef<std::tuple<WeakTrackingVH, unsigned, bool, bool>>
2340 VectorValuesAndScales) {
2342 for (T *V : DeadVals) {
2347 for (T *V : DeadVals) {
2348 if (!V || !Processed.
insert(V).second)
2353 for (
Use &U :
I->operands()) {
2355 OpI && !DeletedInstructions.contains(OpI) && OpI->hasOneUser() &&
2357 !ExternalUseReplacements.contains(OpI) &&
2358 (Entries.
empty() ||
none_of(Entries, [&](
const TreeEntry *Entry) {
2359 return Entry->VectorizedValue == OpI;
2363 I->dropAllReferences();
2365 for (T *V : DeadVals) {
2367 if (!
I->getParent())
2372 cast<Instruction>(U.getUser()));
2374 "trying to erase instruction with users.");
2375 I->removeFromParent();
2379 while (!DeadInsts.
empty()) {
2382 if (!VI || !VI->getParent())
2385 "Live instruction found in dead worklist!");
2386 assert(VI->use_empty() &&
"Instructions with uses are not dead.");
2393 for (
Use &OpU : VI->operands()) {
2394 Value *OpV = OpU.get();
2406 if (!DeletedInstructions.contains(OpI) &&
2407 !ExternalUseReplacements.contains(OpI) &&
2408 (!OpI->getType()->isVectorTy() ||
2410 VectorValuesAndScales,
2411 [&](
const std::tuple<WeakTrackingVH, unsigned, bool, bool>
2412 &V) {
return std::get<0>(V) == OpI; })) &&
2417 VI->removeFromParent();
2419 SE->forgetValue(VI);
2426 return AnalyzedReductionsRoots.count(
I);
2431 AnalyzedReductionsRoots.insert(
I);
2436 return AnalyzedReductionVals.contains(
hash_value(VL));
2441 AnalyzedReductionVals.insert(
hash_value(VL));
2445 return AnalyzedScalars.contains(V);
2449 return AnalyzedBundles.contains(
hash_value(VL));
2457 AnalyzedReductionsRoots.clear();
2458 AnalyzedReductionVals.clear();
2459 AnalyzedBundles.clear();
2460 AnalyzedMinBWVals.clear();
2468 return MustGather.contains(V);
2472 return NonScheduledFirst.contains(V);
2478 auto It = ReassocScalarToTreeEntries.find(V);
2479 return It != ReassocScalarToTreeEntries.end() &&
2480 any_of(It->second, [&](
const TreeEntry *E) {
2481 return !DeletedNodes.contains(E) &&
2482 !TransformedToGatherNodes.contains(E);
2488 assert(V &&
"V cannot be nullptr.");
2491 return any_of(getTreeEntries(V), [&](
const TreeEntry *E) {
2492 return !DeletedNodes.contains(E) && !TransformedToGatherNodes.contains(E);
2500 auto *UI = dyn_cast<Instruction>(U);
2501 return UI && isDeleted(UI);
2524 bool collectValuesToDemote(
2525 const TreeEntry &E,
bool IsProfitableToDemoteRoot,
unsigned &
BitWidth,
2528 bool &IsProfitableToDemote,
bool IsTruncRoot)
const;
2537 void buildReorderableOperands(
2545 void reorderNodeWithReuses(TreeEntry &TE,
ArrayRef<int> Mask)
const;
2548 bool areAllUsersVectorized(
2555 uint64_t getNumScalarInsts(
bool HasTreeLoop);
2560 uint64_t getNumVectorInsts(
bool HasTreeLoop);
2568 const TreeEntry *getOperandEntry(
const TreeEntry *E,
unsigned Idx)
const;
2569 TreeEntry *getOperandEntry(TreeEntry *E,
unsigned Idx) {
2570 return const_cast<TreeEntry *
>(
2571 getOperandEntry(
const_cast<const TreeEntry *
>(E), Idx));
2577 Instruction *getRootEntryInstruction(
const TreeEntry &Entry)
const;
2581 getCastContextHint(
const TreeEntry &TE)
const;
2588 uint64_t getScaleToLoopIterations(
const TreeEntry &TE,
2589 Value *Scalar =
nullptr,
2607 uint64_t getGatherNodeEffectiveScale(
const TreeEntry &TE,
2611 uint64_t getEntryEffectiveScale(
const TreeEntry &TE,
2627 getVectorSpillReloadCost(
const TreeEntry *
E,
Type *ScalarTy,
Type *VecTy,
2633 unsigned InterleaveFactor = 0);
2644 bool ResizeAllowed =
false)
const;
2651 Value *vectorizeOperand(TreeEntry *
E,
unsigned NodeIdx);
2656 template <
typename BVTy,
typename ResTy,
typename... Args>
2657 ResTy processBuildVector(
const TreeEntry *
E,
Type *ScalarTy, Args &...Params);
2662 Value *createBuildVector(
const TreeEntry *
E,
Type *ScalarTy);
2668 Instruction &getLastInstructionInBundle(
const TreeEntry *
E);
2675 std::optional<TargetTransformInfo::ShuffleKind>
2687 unsigned NumParts)
const;
2699 std::optional<TargetTransformInfo::ShuffleKind>
2700 isGatherShuffledSingleRegisterEntry(
2703 unsigned SliceSize);
2717 isGatherShuffledEntry(
2720 unsigned NumParts,
bool ForOrder =
false);
2726 Type *ScalarTy)
const;
2730 void setInsertPointAfterBundle(
const TreeEntry *
E);
2740 bool isFullyVectorizableTinyTree(
bool ForReduction)
const;
2745 void tryToVectorizeGatheredLoads(
2747 std::tuple<BasicBlock *, Value *, Type *>,
2755 void tryToVectorizeSplatGatheredScalars();
2761 collectUserStores(
const BoUpSLP::TreeEntry *TE)
const;
2777 findExternalStoreUsersReorderIndices(TreeEntry *TE)
const;
2781 void reorderGatherNode(TreeEntry &TE);
2788 bool matchesShlZExt(
const TreeEntry &TE,
OrdersType &Order,
bool &IsBSwap,
2789 bool &ForLoads)
const;
2793 bool matchesInversedZExtSelect(
2794 const TreeEntry &SelectTE,
2800 bool matchesSelectOfBits(
const TreeEntry &SelectTE)
const;
2805 TreeEntry(VecTreeTy &Container) : Container(Container) {}
2808 SmallVector<int> getCommonMask()
const {
2809 if (State == TreeEntry::SplitVectorize)
2811 SmallVector<int>
Mask;
2813 addMask(Mask, ReuseShuffleIndices);
2818 SmallVector<int> getSplitMask()
const {
2819 assert(State == TreeEntry::SplitVectorize && !ReorderIndices.empty() &&
2820 "Expected only split vectorize node.");
2821 unsigned CommonVF = std::max<unsigned>(
2822 CombinedEntriesWithIndices.back().second,
2823 Scalars.size() - CombinedEntriesWithIndices.back().second);
2824 const unsigned Scale =
getNumElements(Scalars.front()->getType());
2827 for (
auto [Idx,
I] :
enumerate(ReorderIndices)) {
2831 (Idx >= CombinedEntriesWithIndices.back().second
2832 ? CommonVF - CombinedEntriesWithIndices.back().second * Scale
2841 void reorderSplitNode(
unsigned Idx, ArrayRef<int> Mask,
2842 ArrayRef<int> MaskOrder);
2847 if (
Mask.size() != VL.
size() && VL.
size() == Scalars.size())
2848 return std::equal(VL.
begin(), VL.
end(), Scalars.begin());
2851 [Scalars](
Value *V,
int Idx) {
2852 return isa<PoisonValue>(V) ||
2853 (Idx != PoisonMaskElem && V == Scalars[Idx]);
2856 if (!ReorderIndices.empty()) {
2860 SmallVector<int>
Mask;
2862 if (VL.
size() == Scalars.size())
2863 return IsSame(Scalars, Mask);
2864 if (VL.
size() == ReuseShuffleIndices.size()) {
2865 addMask(Mask, ReuseShuffleIndices);
2866 return IsSame(Scalars, Mask);
2870 return IsSame(Scalars, ReuseShuffleIndices);
2874 bool hasEqualOperands(
const TreeEntry &TE)
const {
2875 if (
TE.getNumOperands() != getNumOperands())
2877 SmallBitVector
Used(getNumOperands());
2878 for (
unsigned I = 0,
E = getNumOperands();
I <
E; ++
I) {
2879 unsigned PrevCount =
Used.count();
2880 for (
unsigned K = 0;
K <
E; ++
K) {
2883 if (getOperand(K) ==
TE.getOperand(
I)) {
2889 if (PrevCount ==
Used.count())
2898 unsigned getVectorFactor()
const {
2899 if (!ReuseShuffleIndices.empty())
2900 return ReuseShuffleIndices.size();
2901 return Scalars.size();
2905 bool isGather()
const {
return State == NeedToGather; }
2911 WeakTrackingVH VectorizedValue =
nullptr;
2923 BlendedLoadVectorize,
2936 enum CombinedOpcode {
2938 MinMax = Instruction::OtherOpsEnd + 1,
2941 ReducedBitcastBSwap,
2942 ReducedBitcastLoads,
2943 ReducedBitcastBSwapLoads,
2946 CombinedOpcode CombinedOp = NotCombinedOp;
2949 SmallVector<int, 4> ReuseShuffleIndices;
2952 SmallVector<unsigned, 4> ReorderIndices;
2960 VecTreeTy &Container;
2963 EdgeInfo UserTreeIndex;
2976 SmallVector<unsigned, 1> StructEVIndices;
2982 SmallVector<ValueList, 2> Operands;
2985 SmallPtrSet<const Value *, 4> CopyableElements;
2989 SmallVector<Value *, 4> ReassocScalars;
2994 SmallBitVector ReassocNegatedOps;
3001 unsigned InterleaveFactor = 0;
3004 bool DoesNotNeedToSchedule =
false;
3008 if (Operands.size() < OpIdx + 1)
3009 Operands.resize(OpIdx + 1);
3010 assert(Operands[OpIdx].
empty() &&
"Already resized?");
3012 "Number of operands is greater than the number of scalars.");
3013 Operands[OpIdx].resize(OpVL.
size());
3018 mutable SmallDenseMap<Value *, unsigned> ValueToLane;
3022 unsigned getInterleaveFactor()
const {
return InterleaveFactor; }
3024 void setInterleave(
unsigned Factor) { InterleaveFactor = Factor; }
3027 void setDoesNotNeedToSchedule() { DoesNotNeedToSchedule =
true; }
3030 bool doesNotNeedToSchedule()
const {
return DoesNotNeedToSchedule; }
3035 setOperand(
I, Operands[
I]);
3039 void reorderOperands(ArrayRef<int> Mask) {
3046 assert(OpIdx < Operands.size() &&
"Off bounds");
3047 return Operands[OpIdx];
3052 assert(OpIdx < Operands.size() &&
"Off bounds");
3053 return Operands[OpIdx];
3057 unsigned getNumOperands()
const {
return Operands.size(); }
3060 Value *getSingleOperand(
unsigned OpIdx)
const {
3061 assert(OpIdx < Operands.size() &&
"Off bounds");
3062 assert(!Operands[OpIdx].
empty() &&
"No operand available");
3063 return Operands[OpIdx][0];
3067 bool isAltShuffle()
const {
return S.isAltShuffle(); }
3069 Instruction *getMatchingMainOpOrAltOp(Instruction *
I)
const {
3070 return S.getMatchingMainOpOrAltOp(
I);
3078 if (
I && getMatchingMainOpOrAltOp(
I))
3080 return S.getMainOp();
3083 void setOperations(
const InstructionsState &S) {
3084 assert(S &&
"InstructionsState is invalid.");
3088 Instruction *getMainOp()
const {
return S.getMainOp(); }
3090 Instruction *getAltOp()
const {
return S.getAltOp(); }
3093 unsigned getOpcode()
const {
return S.getOpcode(); }
3095 unsigned getAltOpcode()
const {
return S.getAltOpcode(); }
3097 bool hasState()
const {
return S.valid(); }
3100 void addCopyableElement(
Value *V) {
3101 assert(S.isCopyableElement(V) &&
"Not a copyable element.");
3102 CopyableElements.insert(V);
3106 bool isCopyableElement(
Value *V)
const {
3107 return CopyableElements.contains(V);
3112 bool isExpandedBinOp(
Value *V)
const {
3113 assert(hasState() &&
"InstructionsState is invalid.");
3114 if (isCopyableElement(V))
3116 return S.isExpandedBinOp(V);
3121 bool isExpandedOperand(Instruction *
I,
unsigned Idx)
const {
3122 assert(hasState() &&
"InstructionsState is invalid.");
3123 if (isCopyableElement(
I))
3125 if (!isExpandedBinOp(
I))
3127 return S.isExpandedOperand(
I, Idx);
3131 bool hasCopyableElements()
const {
return !CopyableElements.empty(); }
3134 void addReassocScalar(
Value *V) { ReassocScalars.push_back(V); }
3137 bool hasReassocScalars()
const {
return !ReassocScalars.empty(); }
3143 void setReassocNegatedOps(
const SmallBitVector &NegatedOps) {
3144 assert(NegatedOps.
size() == getNumOperands() &&
3145 "Signs must cover all operand columns.");
3146 ReassocNegatedOps = NegatedOps;
3150 bool isReassocNegatedOp(
unsigned Idx)
const {
3151 return Idx < ReassocNegatedOps.
size() && ReassocNegatedOps[Idx];
3155 const InstructionsState &getOperations()
const {
return S; }
3159 unsigned findLaneForValue(
Value *V)
const {
3160 auto Res = ValueToLane.try_emplace(V, getVectorFactor());
3162 return Res.first->second;
3163 unsigned &FoundLane = Res.first->getSecond();
3166 auto IsMatch = [
V](
Value *S) {
3169 for (
auto *It =
find_if(Scalars, IsMatch), *End = Scalars.end();
3170 It != End; std::advance(It, 1)) {
3173 FoundLane = std::distance(Scalars.begin(), It);
3174 assert(FoundLane < Scalars.size() &&
"Couldn't find extract lane");
3175 if (!ReorderIndices.empty())
3176 FoundLane = ReorderIndices[FoundLane];
3177 assert(FoundLane < Scalars.size() &&
"Couldn't find extract lane");
3178 if (ReuseShuffleIndices.empty())
3180 if (
auto *RIt =
find(ReuseShuffleIndices, FoundLane);
3181 RIt != ReuseShuffleIndices.end()) {
3182 FoundLane = std::distance(ReuseShuffleIndices.begin(), RIt);
3186 assert(FoundLane < getVectorFactor() &&
"Unable to find given value.");
3193 buildAltOpShuffleMask(
const function_ref<
bool(Instruction *)> IsAltOp,
3194 SmallVectorImpl<int> &Mask,
3195 SmallVectorImpl<Value *> *OpScalars =
nullptr,
3196 SmallVectorImpl<Value *> *AltScalars =
nullptr)
const;
3199 bool isNonPowOf2Vec()
const {
3201 return IsNonPowerOf2;
3204 Value *getOrdered(
unsigned Idx)
const {
3205 if (ReorderIndices.empty())
3206 return Scalars[Idx];
3207 SmallVector<int>
Mask;
3209 return Scalars[
Mask[Idx]];
3215 dbgs() << Idx <<
".\n";
3216 for (
unsigned OpI = 0, OpE = Operands.size(); OpI != OpE; ++OpI) {
3217 dbgs() <<
"Operand " << OpI <<
":\n";
3218 for (
const Value *V : Operands[OpI])
3221 dbgs() <<
"Scalars: \n";
3222 for (
Value *V : Scalars) {
3224 << ((S && S.isExpandedBinOp(V)) ?
" [[Expanded]]\n"
3227 dbgs() <<
"State: ";
3228 if (S && hasCopyableElements())
3229 dbgs() <<
"[[Copyable]] ";
3232 if (InterleaveFactor > 0) {
3233 dbgs() <<
"Vectorize with interleave factor " << InterleaveFactor
3236 dbgs() <<
"Vectorize\n";
3239 case ScatterVectorize:
3240 dbgs() <<
"ScatterVectorize\n";
3242 case StridedVectorize:
3243 dbgs() <<
"StridedVectorize\n";
3245 case ExpandVectorize:
3246 dbgs() <<
"ExpandVectorize\n";
3248 case CompressVectorize:
3249 dbgs() <<
"CompressVectorize\n";
3251 case BlendedLoadVectorize:
3252 dbgs() <<
"BlendedLoadVectorize\n";
3255 dbgs() <<
"NeedToGather\n";
3257 case CombinedVectorize:
3258 dbgs() <<
"CombinedVectorize\n";
3260 case SplitVectorize:
3261 dbgs() <<
"SplitVectorize\n";
3265 dbgs() <<
"MainOp: " << *S.getMainOp() <<
"\n";
3266 dbgs() <<
"AltOp: " << *S.getAltOp() <<
"\n";
3268 dbgs() <<
"MainOp: NULL\n";
3269 dbgs() <<
"AltOp: NULL\n";
3271 dbgs() <<
"VectorizedValue: ";
3272 if (VectorizedValue)
3273 dbgs() << *VectorizedValue <<
"\n";
3276 dbgs() <<
"ReuseShuffleIndices: ";
3277 if (ReuseShuffleIndices.empty())
3280 for (
int ReuseIdx : ReuseShuffleIndices)
3281 dbgs() << ReuseIdx <<
", ";
3283 dbgs() <<
"ReorderIndices: ";
3284 for (
unsigned ReorderIdx : ReorderIndices)
3285 dbgs() << ReorderIdx <<
", ";
3287 dbgs() <<
"UserTreeIndex: ";
3289 dbgs() << UserTreeIndex;
3291 dbgs() <<
"<invalid>";
3293 if (!StructEVIndices.empty()) {
3294 dbgs() <<
"StructEVIndices: ";
3298 if (!CombinedEntriesWithIndices.empty()) {
3299 dbgs() <<
"Combined entries: ";
3301 dbgs() <<
"Entry index " <<
P.first <<
" with offset " <<
P.second;
3312 StringRef Banner)
const {
3313 dbgs() <<
"SLP: " << Banner <<
":\n";
3315 dbgs() <<
"SLP: Costs:\n";
3316 dbgs() <<
"SLP: ReuseShuffleCost = " << ReuseShuffleCost <<
"\n";
3317 dbgs() <<
"SLP: VectorCost = " << VecCost <<
"\n";
3318 dbgs() <<
"SLP: ScalarCost = " << ScalarCost <<
"\n";
3319 dbgs() <<
"SLP: ReuseShuffleCost + VecCost - ScalarCost = "
3320 << ReuseShuffleCost + VecCost - ScalarCost <<
"\n";
3326 const InstructionsState &S,
3328 ArrayRef<int> ReuseShuffleIndices = {}) {
3329 auto Invalid = ScheduleBundle::invalid();
3330 return newTreeEntry(VL,
Invalid, S, UserTreeIdx, ReuseShuffleIndices);
3335 const InstructionsState &S,
3337 ArrayRef<int> ReuseShuffleIndices = {},
3338 ArrayRef<unsigned> ReorderIndices = {},
3339 unsigned InterleaveFactor = 0) {
3340 TreeEntry::EntryState EntryState =
3341 Bundle ? TreeEntry::Vectorize : TreeEntry::NeedToGather;
3342 TreeEntry *
E = newTreeEntry(VL, EntryState, Bundle, S, UserTreeIdx,
3343 ReuseShuffleIndices, ReorderIndices);
3344 if (
E && InterleaveFactor > 0)
3345 E->setInterleave(InterleaveFactor);
3350 TreeEntry::EntryState EntryState,
3351 ScheduleBundle &Bundle,
const InstructionsState &S,
3353 ArrayRef<int> ReuseShuffleIndices = {},
3354 ArrayRef<unsigned> ReorderIndices = {}) {
3355 assert(((!Bundle && (EntryState == TreeEntry::NeedToGather ||
3356 EntryState == TreeEntry::SplitVectorize)) ||
3357 (Bundle && EntryState != TreeEntry::NeedToGather &&
3358 EntryState != TreeEntry::SplitVectorize)) &&
3359 "Need to vectorize gather entry?");
3361 if (GatheredLoadsEntriesFirst.has_value() &&
3362 EntryState == TreeEntry::NeedToGather && S &&
3363 S.
getOpcode() == Instruction::Load && UserTreeIdx.EdgeIdx == UINT_MAX &&
3364 !UserTreeIdx.UserTE)
3366 VectorizableTree.push_back(std::make_unique<TreeEntry>(VectorizableTree));
3367 TreeEntry *
Last = VectorizableTree.back().get();
3368 Last->Idx = VectorizableTree.size() - 1;
3369 Last->State = EntryState;
3370 if (UserTreeIdx.UserTE)
3371 OperandsToTreeEntry.try_emplace(
3372 std::make_pair(UserTreeIdx.UserTE, UserTreeIdx.EdgeIdx),
Last);
3373 Last->ReuseShuffleIndices.append(ReuseShuffleIndices.begin(),
3374 ReuseShuffleIndices.end());
3375 if (ReorderIndices.
empty()) {
3378 Last->setOperations(S);
3381 Last->Scalars.assign(VL.
size(),
nullptr);
3383 [VL](
unsigned Idx) ->
Value * {
3384 if (Idx >= VL.size())
3385 return UndefValue::get(VL.front()->getType());
3390 Last->setOperations(S);
3391 Last->ReorderIndices.append(ReorderIndices.
begin(), ReorderIndices.
end());
3393 if (EntryState == TreeEntry::SplitVectorize) {
3394 assert(S &&
"Split nodes must have operations.");
3395 Last->setOperations(S);
3396 SmallPtrSet<Value *, 4> Processed;
3397 for (
Value *V : VL) {
3401 auto It = ScalarsInSplitNodes.find(V);
3402 if (It == ScalarsInSplitNodes.end()) {
3403 ScalarsInSplitNodes.try_emplace(V).first->getSecond().push_back(
Last);
3404 (void)Processed.
insert(V);
3405 }
else if (Processed.
insert(V).second) {
3407 "Value already associated with the node.");
3408 It->getSecond().push_back(
Last);
3411 }
else if (!
Last->isGather()) {
3417 Last->setDoesNotNeedToSchedule();
3418 SmallPtrSet<Value *, 4> Processed;
3419 for (
Value *V : VL) {
3423 Last->addCopyableElement(V);
3426 auto It = ScalarToTreeEntries.find(V);
3427 if (It == ScalarToTreeEntries.end()) {
3428 ScalarToTreeEntries.try_emplace(V).first->getSecond().push_back(
Last);
3429 (void)Processed.
insert(V);
3430 }
else if (Processed.
insert(V).second) {
3432 "Value already associated with the node.");
3433 It->getSecond().push_back(
Last);
3437 assert((!Bundle.getBundle().empty() ||
Last->doesNotNeedToSchedule()) &&
3438 "Bundle and VL out of sync");
3439 if (!Bundle.getBundle().empty()) {
3440#if !defined(NDEBUG) || defined(EXPENSIVE_CHECKS)
3441 auto *BundleMember = Bundle.getBundle().begin();
3442 SmallPtrSet<Value *, 4> Processed;
3443 for (
Value *V : VL) {
3448 assert(BundleMember == Bundle.getBundle().end() &&
3449 "Bundle and VL out of sync");
3451 Bundle.setTreeEntry(
Last);
3455 bool AllConstsOrCasts =
true;
3456 for (
Value *V : VL) {
3459 Last->addCopyableElement(V);
3462 AllConstsOrCasts &=
I &&
I->getType()->isIntegerTy();
3463 if (UserTreeIdx.EdgeIdx != UINT_MAX || !UserTreeIdx.UserTE ||
3464 !UserTreeIdx.UserTE->isGather())
3465 ValueToGatherNodes.try_emplace(V).first->getSecond().insert(
Last);
3468 if (AllConstsOrCasts)
3470 std::make_pair(std::numeric_limits<unsigned>::max(), 1);
3471 MustGather.insert_range(VL);
3474 if (UserTreeIdx.UserTE)
3475 Last->UserTreeIndex = UserTreeIdx;
3481 TreeEntry::VecTreeTy VectorizableTree;
3486 for (
unsigned Id = 0, IdE = VectorizableTree.size(); Id != IdE; ++Id) {
3487 VectorizableTree[
Id]->dump();
3488 if (TransformedToGatherNodes.contains(VectorizableTree[Id].get()))
3489 dbgs() <<
"[[TRANSFORMED TO GATHER]]";
3490 else if (DeletedNodes.contains(VectorizableTree[Id].get()))
3491 dbgs() <<
"[[DELETED NODE]]";
3499 assert(V &&
"V cannot be nullptr.");
3500 auto It = ScalarToTreeEntries.find(V);
3501 if (It == ScalarToTreeEntries.end())
3503 return It->getSecond();
3508 assert(V &&
"V cannot be nullptr.");
3509 auto It = ScalarsInSplitNodes.find(V);
3510 if (It == ScalarsInSplitNodes.end())
3512 return It->getSecond();
3517 bool SameVF =
false)
const {
3518 assert(V &&
"V cannot be nullptr.");
3519 for (TreeEntry *TE : ScalarToTreeEntries.lookup(V))
3520 if ((!SameVF ||
TE->getVectorFactor() == VL.
size()) &&
TE->isSame(VL))
3527 class ScalarsVectorizationLegality {
3528 InstructionsState S;
3530 bool TryToFindDuplicates;
3531 bool TrySplitVectorize;
3534 ScalarsVectorizationLegality(InstructionsState S,
bool IsLegal,
3535 bool TryToFindDuplicates =
true,
3536 bool TrySplitVectorize =
false)
3537 : S(S), IsLegal(IsLegal), TryToFindDuplicates(TryToFindDuplicates),
3538 TrySplitVectorize(TrySplitVectorize) {
3539 assert((!IsLegal || (S.valid() && TryToFindDuplicates)) &&
3540 "Inconsistent state");
3542 const InstructionsState &getInstructionsState()
const {
return S; };
3543 bool isLegal()
const {
return IsLegal; }
3544 bool tryToFindDuplicates()
const {
return TryToFindDuplicates; }
3545 bool trySplitVectorize()
const {
return TrySplitVectorize; }
3550 ScalarsVectorizationLegality
3552 const EdgeInfo &UserTreeIdx)
const;
3556 TreeEntry::EntryState getScalarsVectorizationState(
3558 bool IsScatterVectorizeUserTE,
OrdersType &CurrentOrder,
3560 SmallVectorImpl<int> &ReuseShuffleIndices);
3563 SmallDenseMap<Value *, SmallVector<TreeEntry *>> ScalarToTreeEntries;
3566 SmallPtrSet<const TreeEntry *, 8> DeletedNodes;
3570 SmallDenseMap<const TreeEntry *, InstructionCost> TransformedToGatherNodes;
3573 SmallDenseMap<std::pair<const TreeEntry *, unsigned>, TreeEntry *>
3574 OperandsToTreeEntry;
3577 SmallDenseMap<Value *, SmallVector<TreeEntry *>> ScalarsInSplitNodes;
3580 SmallDenseMap<Value *, unsigned> InstrElementSize;
3587 SmallDenseMap<const Value *, SmallVector<const TreeEntry *>>
3588 ReassocScalarToTreeEntries;
3593 SmallPtrSet<const Value *, 8> KeptReassocScalars;
3604 SmallDenseMap<const TreeEntry *, WeakTrackingVH> EntryToLastInstruction;
3608 SmallDenseMap<const Instruction *, Instruction *> LastInstructionToPos;
3613 SetVector<const TreeEntry *> PostponedGathers;
3615 using ValueToGatherNodesMap =
3616 DenseMap<Value *, SmallSetVector<const TreeEntry *, 4>>;
3617 ValueToGatherNodesMap ValueToGatherNodes;
3619 SmallDenseMap<TreeEntry *, StridedPtrInfo> TreeEntryToStridedPtrInfoMap;
3624 SetVector<unsigned> LoadEntriesToVectorize;
3627 bool IsGraphTransformMode =
false;
3630 std::optional<unsigned> GatheredLoadsEntriesFirst;
3635 SmallVector<TreeEntry *> SplatGatheredScalarsRoots;
3638 SmallDenseMap<
const TreeEntry *,
3639 std::tuple<SmallVector<int>,
VectorType *, unsigned,
bool>>
3640 CompressEntryToData;
3644 SmallVector<const Loop *> CurrentLoopNest;
3648 SmallVector<const SCEV *> MergedLoopBTCs;
3651 SmallDenseMap<const Loop *, SmallVector<const Loop *>> LoopToLoopNest;
3656 SmallDenseMap<const Loop *, uint64_t> LoopNestScaleCache;
3659 struct ExternalUser {
3660 ExternalUser(
Value *S, llvm::User *U,
const TreeEntry &E,
unsigned L)
3661 : Scalar(S), User(
U), E(E), Lane(
L) {}
3664 Value *Scalar =
nullptr;
3667 llvm::User *User =
nullptr;
3675 using UserList = SmallVector<ExternalUser, 16>;
3681 bool isAliased(
const MemoryLocation &Loc1, Instruction *Inst1,
3682 Instruction *Inst2) {
3685 AliasCacheKey
Key = std::make_pair(Inst1, Inst2);
3686 auto Res = AliasCache.try_emplace(
Key);
3688 return Res.first->second;
3689 bool Aliased =
isModOrRefSet(BatchAA.getModRefInfo(Inst2, Loc1));
3691 Res.first->getSecond() = Aliased;
3698 bool isRuntimeCheckableAliasPair(Instruction *Inst1, Instruction *Inst2);
3703 bool recordRuntimeAliasCheck(BasicBlock *BB, Instruction *Inst1,
3704 Instruction *Inst2);
3708 void versionBlocksForRuntimeChecks();
3713 Value *emitRuntimeAliasCheck(IRBuilderBase &Builder, SCEVExpander &Exp);
3716 struct RuntimeAliasCheckInfo {
3721 SmallSetVector<std::pair<const Value *, const Value *>, 4> BasePairs;
3723 SmallMapVector<const Value *, std::pair<const SCEV *, const SCEV *>, 4>
3736 bool TryRuntimeAliasChecks =
false;
3739 RuntimeAliasCheckInfo RTChecks;
3744 SmallDenseSet<std::pair<const Value *, const Value *>, 4>, 2>
3745 VersionedBlockCheckedPairs;
3748 SmallPtrSet<BasicBlock *, 4> ScalarFallbackBlocks;
3752 SmallPtrSet<BasicBlock *, 8> FailedRuntimeChecksBlocks;
3757 bool isCoveredByExistingVersionCheck(BasicBlock *BB, Instruction *Inst1,
3758 Instruction *Inst2)
const;
3762 bool HasRuntimeCheckableBlockers =
false;
3766 bool HasNonCheckableMemBlocker =
false;
3769 bool RTChecksFinalized =
false;
3773 bool CFGChanged =
false;
3776 SmallVector<Instruction *> RTOrigBodyOrder;
3778 using AliasCacheKey = std::pair<Instruction *, Instruction *>;
3782 SmallDenseMap<AliasCacheKey, bool> AliasCache;
3787 BatchAAResults BatchAA;
3794 DenseSet<Instruction *> DeletedInstructions;
3797 SmallPtrSet<Instruction *, 16> AnalyzedReductionsRoots;
3800 DenseSet<size_t> AnalyzedReductionVals;
3803 SmallDenseSet<size_t, 8> AnalyzedBundles;
3806 SmallPtrSet<const Value *, 32> AnalyzedScalars;
3809 mutable SmallDenseMap<std::tuple<Type *, Type *, unsigned>,
unsigned>
3814 DenseSet<Value *> AnalyzedMinBWVals;
3820 UserList ExternalUses;
3824 SmallPtrSet<Value *, 4> ExternalUsesAsOriginalScalar;
3828 SmallPtrSet<Value *, 4> ExternalUsesWithNonUsers;
3833 SmallPtrSet<Value *, 4> ExternalUseReplacements;
3836 SmallPtrSet<const Value *, 32> EphValues;
3840 SetVector<Instruction *> GatherShuffleExtractSeq;
3843 DenseSet<BasicBlock *> CSEBlocks;
3846 DenseSet<size_t> ListOfKnonwnNonVectorizableLoads;
3853 class ScheduleEntity {
3854 friend class ScheduleBundle;
3855 friend class ScheduleData;
3856 friend class ScheduleCopyableData;
3859 enum class Kind { ScheduleData, ScheduleBundle, ScheduleCopyableData };
3860 Kind getKind()
const {
return K; }
3861 ScheduleEntity(Kind K) : K(K) {}
3865 int SchedulingPriority = 0;
3868 bool IsScheduled =
false;
3870 const Kind K = Kind::ScheduleData;
3873 ScheduleEntity() =
delete;
3875 void setSchedulingPriority(
int Priority) { SchedulingPriority = Priority; }
3876 int getSchedulingPriority()
const {
return SchedulingPriority; }
3877 bool isReady()
const {
3879 return SD->isReady();
3881 return CD->isReady();
3887 bool hasValidDependencies()
const {
3889 return SD->hasValidDependencies();
3891 return CD->hasValidDependencies();
3895 int getUnscheduledDeps()
const {
3897 return SD->getUnscheduledDeps();
3899 return CD->getUnscheduledDeps();
3903 int incrementUnscheduledDeps(
int Incr) {
3905 return SD->incrementUnscheduledDeps(Incr);
3909 int getDependencies()
const {
3911 return SD->getDependencies();
3917 return SD->getInst();
3922 bool isScheduled()
const {
return IsScheduled; }
3923 void setScheduled(
bool Scheduled) { IsScheduled = Scheduled; }
3925 static bool classof(
const ScheduleEntity *) {
return true; }
3927#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3928 void dump(raw_ostream &OS)
const {
3930 return SD->dump(OS);
3932 return CD->dump(OS);
3943#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3945 const BoUpSLP::ScheduleEntity &SE) {
3955 class ScheduleData final :
public ScheduleEntity {
3959 enum { InvalidDeps = -1 };
3961 ScheduleData() : ScheduleEntity(Kind::ScheduleData) {}
3962 static bool classof(
const ScheduleEntity *Entity) {
3963 return Entity->getKind() == Kind::ScheduleData;
3966 void init(
int BlockSchedulingRegionID, Instruction *
I) {
3967 NextLoadStore =
nullptr;
3968 IsScheduled =
false;
3969 SchedulingRegionID = BlockSchedulingRegionID;
3970 clearDependencies();
3976 if (hasValidDependencies()) {
3977 assert(UnscheduledDeps <= Dependencies &&
"invariant");
3979 assert(UnscheduledDeps == Dependencies &&
"invariant");
3983 assert(hasValidDependencies() && UnscheduledDeps == 0 &&
3984 "unexpected scheduled state");
3991 bool hasValidDependencies()
const {
return Dependencies != InvalidDeps; }
3995 bool isReady()
const {
return UnscheduledDeps == 0 && !IsScheduled; }
4000 int incrementUnscheduledDeps(
int Incr) {
4001 assert(hasValidDependencies() &&
4002 "increment of unscheduled deps would be meaningless");
4003 UnscheduledDeps += Incr;
4004 assert(UnscheduledDeps >= 0 &&
4005 "Expected valid number of unscheduled deps");
4006 return UnscheduledDeps;
4011 void resetUnscheduledDeps() { UnscheduledDeps = Dependencies; }
4014 void clearDependencies() {
4015 clearDirectDependencies();
4016 MemoryDependencies.clear();
4017 ControlDependencies.clear();
4024 void clearDirectDependencies() {
4025 Dependencies = InvalidDeps;
4026 resetUnscheduledDeps();
4027 IsScheduled =
false;
4031 int getUnscheduledDeps()
const {
return UnscheduledDeps; }
4033 int getDependencies()
const {
return Dependencies; }
4035 void initDependencies() { Dependencies = 0; }
4037 void incDependencies() { Dependencies++; }
4040 int getSchedulingRegionID()
const {
return SchedulingRegionID; }
4047 return MemoryDependencies;
4050 void addMemoryDependency(ScheduleData *Dep) {
4051 MemoryDependencies.push_back(Dep);
4055 return ControlDependencies;
4058 void addControlDependency(ScheduleData *Dep) {
4059 ControlDependencies.push_back(Dep);
4062 ScheduleData *getNextLoadStore()
const {
return NextLoadStore; }
4063 void setNextLoadStore(ScheduleData *
Next) { NextLoadStore =
Next; }
4065 void dump(raw_ostream &OS)
const { OS << *Inst; }
4077 ScheduleData *NextLoadStore =
nullptr;
4081 SmallVector<ScheduleData *> MemoryDependencies;
4087 SmallVector<ScheduleData *> ControlDependencies;
4091 int SchedulingRegionID = 0;
4097 int Dependencies = InvalidDeps;
4103 int UnscheduledDeps = InvalidDeps;
4108 const BoUpSLP::ScheduleData &SD) {
4114 class ScheduleBundle final :
public ScheduleEntity {
4118 bool IsValid =
true;
4120 TreeEntry *TE =
nullptr;
4121 ScheduleBundle(
bool IsValid)
4122 : ScheduleEntity(Kind::ScheduleBundle), IsValid(IsValid) {}
4125 ScheduleBundle() : ScheduleEntity(Kind::ScheduleBundle) {}
4126 static bool classof(
const ScheduleEntity *Entity) {
4127 return Entity->getKind() == Kind::ScheduleBundle;
4132 for (
const ScheduleEntity *SD : Bundle) {
4133 if (SD->hasValidDependencies()) {
4134 assert(SD->getUnscheduledDeps() <= SD->getDependencies() &&
4137 assert(SD->getUnscheduledDeps() == SD->getDependencies() &&
4141 if (isScheduled()) {
4142 assert(SD->hasValidDependencies() && SD->getUnscheduledDeps() == 0 &&
4143 "unexpected scheduled state");
4149 int unscheduledDepsInBundle()
const {
4150 assert(*
this &&
"bundle must not be empty");
4152 for (
const ScheduleEntity *BundleMember : Bundle) {
4153 if (BundleMember->getUnscheduledDeps() == ScheduleData::InvalidDeps)
4154 return ScheduleData::InvalidDeps;
4155 Sum += BundleMember->getUnscheduledDeps();
4163 bool hasValidDependencies()
const {
4164 return all_of(Bundle, [](
const ScheduleEntity *SD) {
4165 return SD->hasValidDependencies();
4171 bool isReady()
const {
4172 assert(*
this &&
"bundle must not be empty");
4173 return unscheduledDepsInBundle() == 0 && !isScheduled();
4181 void add(ScheduleEntity *SD) { Bundle.push_back(SD); }
4184 void setTreeEntry(TreeEntry *TE) { this->TE = TE; }
4185 TreeEntry *getTreeEntry()
const {
return TE; }
4187 static ScheduleBundle invalid() {
return {
false}; }
4189 operator bool()
const {
return IsValid; }
4192 void dump(raw_ostream &OS)
const {
4201 OS << *SD->getInst();
4215 const BoUpSLP::ScheduleBundle &Bundle) {
4226 class ScheduleCopyableData final :
public ScheduleEntity {
4233 int SchedulingRegionID = 0;
4235 ScheduleBundle &Bundle;
4238 ScheduleCopyableData(
int BlockSchedulingRegionID,
Instruction *
I,
4239 const EdgeInfo &EI, ScheduleBundle &Bundle)
4240 : ScheduleEntity(Kind::ScheduleCopyableData), Inst(
I), EI(EI),
4241 SchedulingRegionID(BlockSchedulingRegionID), Bundle(Bundle) {}
4242 static bool classof(
const ScheduleEntity *Entity) {
4243 return Entity->getKind() == Kind::ScheduleCopyableData;
4248 if (hasValidDependencies()) {
4249 assert(UnscheduledDeps <= Dependencies &&
"invariant");
4251 assert(UnscheduledDeps == Dependencies &&
"invariant");
4255 assert(hasValidDependencies() && UnscheduledDeps == 0 &&
4256 "unexpected scheduled state");
4263 bool hasValidDependencies()
const {
4264 return Dependencies != ScheduleData::InvalidDeps;
4269 bool isReady()
const {
return UnscheduledDeps == 0 && !IsScheduled; }
4274 int incrementUnscheduledDeps(
int Incr) {
4275 assert(hasValidDependencies() &&
4276 "increment of unscheduled deps would be meaningless");
4277 UnscheduledDeps += Incr;
4278 assert(UnscheduledDeps >= 0 &&
"invariant");
4279 return UnscheduledDeps;
4284 void resetUnscheduledDeps() { UnscheduledDeps = Dependencies; }
4287 int getUnscheduledDeps()
const {
return UnscheduledDeps; }
4289 int getDependencies()
const {
return Dependencies; }
4291 void initDependencies() { Dependencies = 0; }
4293 void incDependencies() { Dependencies++; }
4296 int getSchedulingRegionID()
const {
return SchedulingRegionID; }
4302 void clearDependencies() {
4303 Dependencies = ScheduleData::InvalidDeps;
4304 UnscheduledDeps = ScheduleData::InvalidDeps;
4305 IsScheduled =
false;
4309 const EdgeInfo &getEdgeInfo()
const {
return EI; }
4312 ScheduleBundle &getBundle() {
return Bundle; }
4313 const ScheduleBundle &getBundle()
const {
return Bundle; }
4315#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
4316 void dump(raw_ostream &OS)
const { OS <<
"[Copyable]" << *getInst(); }
4327 int Dependencies = ScheduleData::InvalidDeps;
4333 int UnscheduledDeps = ScheduleData::InvalidDeps;
4363 struct BlockScheduling {
4365 : BB(BB), ChunkSize(BB->
size()), ChunkPos(ChunkSize) {}
4368 ScheduledBundles.clear();
4369 ScheduledBundlesList.
clear();
4370 ScheduleCopyableDataMap.clear();
4371 ScheduleCopyableDataMapByInst.clear();
4372 ScheduleCopyableDataMapByInstUser.clear();
4373 ScheduleCopyableDataMapByUsers.clear();
4375 RecalcCopyableOperandDeps.
clear();
4376 IgnoredMemDeps.clear();
4377 ScheduleStart =
nullptr;
4378 ScheduleEnd =
nullptr;
4379 FirstLoadStoreInRegion =
nullptr;
4380 LastLoadStoreInRegion =
nullptr;
4381 RegionHasStackSave =
false;
4385 ScheduleRegionSizeLimit -= ScheduleRegionSize;
4388 ScheduleRegionSize = 0;
4392 ++SchedulingRegionID;
4395 ScheduleData *getScheduleData(Instruction *
I) {
4398 if (BB !=
I->getParent())
4401 ScheduleData *SD = ScheduleDataMap.lookup(
I);
4402 if (SD && isInSchedulingRegion(*SD))
4407 ScheduleData *getScheduleData(
Value *V) {
4413 ScheduleCopyableData *getScheduleCopyableData(
const EdgeInfo &EI,
4414 const Value *V)
const {
4415 if (ScheduleCopyableDataMap.empty())
4417 auto It = ScheduleCopyableDataMap.find(std::make_pair(EI, V));
4418 if (It == ScheduleCopyableDataMap.end())
4420 ScheduleCopyableData *SD = It->getSecond().get();
4421 if (!isInSchedulingRegion(*SD))
4429 getScheduleCopyableData(
const Value *User,
unsigned OperandIdx,
4431 if (ScheduleCopyableDataMapByInstUser.empty())
4433 const auto It = ScheduleCopyableDataMapByInstUser.find(
4434 std::make_pair(std::make_pair(User, OperandIdx), V));
4435 if (It == ScheduleCopyableDataMapByInstUser.end())
4438 for (ScheduleCopyableData *SD : It->getSecond()) {
4439 if (isInSchedulingRegion(*SD))
4453 bool areAllOperandsReplacedByCopyableData(Instruction *User,
4457 if (ScheduleCopyableDataMap.empty())
4459 SmallDenseMap<TreeEntry *, unsigned> PotentiallyReorderedEntriesCount;
4461 if (Entries.
empty())
4463 unsigned CurNumOps = 0;
4464 for (
const Use &U :
User->operands()) {
4470 for (TreeEntry *TE : Entries) {
4472 bool IsNonSchedulableWithParentPhiNode =
4473 TE->doesNotNeedToSchedule() &&
TE->UserTreeIndex &&
4474 TE->UserTreeIndex.UserTE->hasState() &&
4475 TE->UserTreeIndex.UserTE->State != TreeEntry::SplitVectorize &&
4476 TE->UserTreeIndex.UserTE->getOpcode() == Instruction::PHI;
4479 if (IsNonSchedulableWithParentPhiNode) {
4480 SmallPtrSet<Value *, 4> ParentsUniqueUsers;
4481 const TreeEntry *ParentTE =
TE->UserTreeIndex.UserTE;
4482 for (
Value *V : ParentTE->Scalars) {
4486 if (ParentsUniqueUsers.
insert(
PHI).second &&
4491 Inc =
count(
TE->Scalars, User);
4499 bool IsCommutativeUser =
4502 if (!IsCommutativeUser) {
4513 (!IsCommutativeUser ||
4521 "Expected commutative user with 2 first commutable operands");
4522 bool IsCommutativeWithSameOps =
4523 IsCommutativeUser &&
User->getOperand(0) ==
User->getOperand(1);
4524 if ((!IsCommutativeUser || IsCommutativeWithSameOps) &&
4526 User->getOperand(0) ==
User->getOperand(1))) {
4532 if (
TE->hasReassocScalars()) {
4533 bool ReplacedByCopyable =
false;
4534 for (
auto It =
find(
TE->Scalars, User); It !=
TE->Scalars.end();
4537 int Lane = std::distance(
TE->Scalars.begin(), It);
4539 ReplacedByCopyable |=
4540 TE->getOperand(OpIdx)[Lane] ==
Op &&
4541 getScheduleCopyableData(EdgeInfo(TE, OpIdx),
Op);
4543 if (ReplacedByCopyable)
4547 EdgeInfo EI(TE,
U.getOperandNo());
4548 if (getScheduleCopyableData(EI,
Op))
4555 PotentiallyReorderedEntriesCount.
try_emplace(TE, 0)
4556 .first->getSecond() += Inc;
4559 if (PotentiallyReorderedEntriesCount.
empty())
4562 for (
auto &
P : PotentiallyReorderedEntriesCount) {
4563 SmallPtrSet<Value *, 4> ParentsUniqueUsers;
4564 bool IsNonSchedulableWithParentPhiNode =
4565 P.first->doesNotNeedToSchedule() &&
P.first->UserTreeIndex &&
4566 P.first->UserTreeIndex.UserTE->hasState() &&
4567 P.first->UserTreeIndex.UserTE->State != TreeEntry::SplitVectorize &&
4568 P.first->UserTreeIndex.UserTE->getOpcode() == Instruction::PHI;
4569 auto *It =
find(
P.first->Scalars, User);
4571 assert(It !=
P.first->Scalars.end() &&
4572 "User is not in the tree entry");
4573 int Lane = std::distance(
P.first->Scalars.begin(), It);
4574 assert(Lane >= 0 &&
"Lane is not found");
4576 !
P.first->ReorderIndices.empty())
4577 Lane =
P.first->ReorderIndices[Lane];
4578 assert(Lane <
static_cast<int>(
P.first->Scalars.size()) &&
4579 "Couldn't find extract lane");
4582 if (IsNonSchedulableWithParentPhiNode) {
4583 const TreeEntry *ParentTE =
P.first->UserTreeIndex.UserTE;
4585 if (!ParentsUniqueUsers.
insert(User).second) {
4593 for (
unsigned OpIdx :
4595 ?
P.first->getNumOperands()
4597 P.first->getMainOp()))) {
4598 if (
P.first->getOperand(OpIdx)[Lane] ==
Op &&
4599 getScheduleCopyableData(EdgeInfo(
P.first, OpIdx),
Op))
4604 }
while (It !=
P.first->Scalars.end());
4606 return all_of(PotentiallyReorderedEntriesCount,
4607 [&](
const std::pair<const TreeEntry *, unsigned> &
P) {
4608 return P.second ==
NumOps - 1;
4613 getScheduleCopyableData(
const Instruction *
I)
const {
4614 if (ScheduleCopyableDataMapByInst.empty())
4616 const auto It = ScheduleCopyableDataMapByInst.find(
I);
4617 if (It == ScheduleCopyableDataMapByInst.end())
4620 for (ScheduleCopyableData *SD : It->getSecond()) {
4621 if (isInSchedulingRegion(*SD))
4628 getScheduleCopyableDataUsers(
const Instruction *User)
const {
4629 if (ScheduleCopyableDataMapByUsers.empty())
4631 const auto It = ScheduleCopyableDataMapByUsers.find(User);
4632 if (It == ScheduleCopyableDataMapByUsers.end())
4635 for (ScheduleCopyableData *SD : It->getSecond()) {
4636 if (isInSchedulingRegion(*SD))
4647 void markCopyableDepsForRecalc(
const TreeEntry &TE) {
4649 for (
Value *V :
TE.getOperand(OpIdx))
4651 if (ScheduleData *SD = getScheduleData(
I);
4652 SD && !getScheduleCopyableData(
I).empty())
4653 RecalcCopyableOperandDeps.
insert(SD);
4656 ScheduleCopyableData &addScheduleCopyableData(
const EdgeInfo &EI,
4658 int SchedulingRegionID,
4659 ScheduleBundle &Bundle) {
4660 assert(!getScheduleCopyableData(EI,
I) &&
"already in the map");
4661 ScheduleCopyableData *CD =
4662 ScheduleCopyableDataMap
4663 .try_emplace(std::make_pair(EI,
I),
4664 std::make_unique<ScheduleCopyableData>(
4665 SchedulingRegionID,
I, EI, Bundle))
4668 ScheduleCopyableDataMapByInst[
I].push_back(CD);
4672 assert(It !=
Op.end() &&
"Lane not set");
4673 SmallPtrSet<Instruction *, 4> Visited;
4675 int Lane = std::distance(
Op.begin(), It);
4676 assert(Lane >= 0 &&
"Lane not set");
4678 !EI.UserTE->ReorderIndices.empty())
4679 Lane = EI.UserTE->ReorderIndices[Lane];
4680 assert(Lane <
static_cast<int>(EI.UserTE->Scalars.size()) &&
4681 "Couldn't find extract lane");
4683 if (!Visited.
insert(In).second) {
4687 ScheduleCopyableDataMapByInstUser
4688 .try_emplace(std::make_pair(std::make_pair(In, EI.EdgeIdx),
I))
4691 ScheduleCopyableDataMapByUsers.try_emplace(
I)
4698 EdgeInfo UserEI = EI.UserTE->UserTreeIndex;
4699 if (ScheduleCopyableData *UserCD =
4700 getScheduleCopyableData(UserEI, In))
4701 ScheduleCopyableDataMapByUsers[
I].remove(UserCD);
4704 }
while (It !=
Op.end());
4706 ScheduleCopyableDataMapByUsers.try_emplace(
I).first->getSecond().insert(
4716 auto It = ScheduledBundles.find(
I);
4717 if (It == ScheduledBundles.end())
4719 return It->getSecond();
4723 bool isInSchedulingRegion(
const ScheduleEntity &SD)
const {
4725 return Data->getSchedulingRegionID() == SchedulingRegionID;
4727 return CD->getSchedulingRegionID() == SchedulingRegionID;
4729 [&](
const ScheduleEntity *BundleMember) {
4730 return isInSchedulingRegion(*BundleMember);
4736 template <
typename ReadyListType>
4737 void schedule(
const BoUpSLP &R,
const InstructionsState &S,
4738 const EdgeInfo &EI, ScheduleEntity *
Data,
4739 ReadyListType &ReadyList) {
4740 auto ProcessBundleMember = [&](ScheduleEntity *BundleMember,
4745 auto DecrUnsched = [&](
auto *
Data,
bool IsControl =
false) {
4746 if ((IsControl ||
Data->hasValidDependencies()) &&
4747 Data->incrementUnscheduledDeps(-1) == 0) {
4754 CopyableBundle.
push_back(&CD->getBundle());
4755 Bundles = CopyableBundle;
4757 Bundles = getScheduleBundles(
Data->getInst());
4759 if (!Bundles.
empty()) {
4760 for (ScheduleBundle *Bundle : Bundles) {
4761 if (Bundle->unscheduledDepsInBundle() == 0) {
4762 assert(!Bundle->isScheduled() &&
4763 "already scheduled bundle gets ready");
4764 ReadyList.insert(Bundle);
4766 <<
"SLP: gets ready: " << *Bundle <<
"\n");
4772 "already scheduled bundle gets ready");
4774 "Expected non-copyable data");
4775 ReadyList.insert(
Data);
4782 if (!ScheduleCopyableDataMap.empty()) {
4784 getScheduleCopyableData(User, OpIdx,
I);
4785 bool ReleasedAsCopyable =
false;
4786 for (ScheduleCopyableData *CD : CopyableData) {
4792 if (CD->getEdgeInfo().UserTE->isCopyableElement(User))
4794 DecrUnsched(CD,
false);
4795 ReleasedAsCopyable =
true;
4797 if (ReleasedAsCopyable)
4800 if (ScheduleData *OpSD = getScheduleData(
I))
4801 DecrUnsched(OpSD,
false);
4807 if (!Bundles.empty()) {
4808 auto *
In = BundleMember->getInst();
4810 SmallDenseMap<const Instruction *, unsigned> OperandsUses;
4811 unsigned TotalOpCount = 0;
4814 TotalOpCount = OperandsUses[
In] = 1;
4816 for (
const Use &U :
In->operands()) {
4819 unsigned ExtraDeps = 1;
4821 for (ScheduleBundle *Bundle : Bundles) {
4822 if (
const TreeEntry *TE = Bundle->getTreeEntry()) {
4823 if (
TE->isExpandedBinOp(In))
4829 Res.first->getSecond() += ExtraDeps;
4830 TotalOpCount += ExtraDeps;
4837 bool FoundInOpColumns =
false;
4840 auto DecrUnschedForInst =
4842 SmallDenseSet<std::pair<const ScheduleEntity *, unsigned>>
4844 bool IsExpandedOperand =
false,
4845 bool CopyableDepsOnly =
false) {
4846 if (!ScheduleCopyableDataMap.empty()) {
4847 const EdgeInfo EI = {UserTE, OpIdx};
4848 if (ScheduleCopyableData *CD =
4849 getScheduleCopyableData(EI,
I)) {
4850 if (!Checked.insert(std::make_pair(CD, OpIdx)).second)
4852 DecrUnsched(CD,
false);
4856 if (CopyableDepsOnly)
4858 auto It = OperandsUses.
find(
I);
4859 if (It == OperandsUses.
end()) {
4863 <<
" not modeled as a direct operand of "
4864 << *In <<
", skipping.\n");
4867 if (It->second > 0) {
4868 if (ScheduleData *OpSD = getScheduleData(
I)) {
4869 if (!IsExpandedOperand &&
4870 !Checked.insert(std::make_pair(OpSD, OpIdx)).second)
4873 assert(TotalOpCount > 0 &&
"No more operands to decrement");
4875 DecrUnsched(OpSD,
false);
4878 assert(TotalOpCount > 0 &&
"No more operands to decrement");
4884 SmallDenseSet<std::pair<const ScheduleEntity *, unsigned>> Checked;
4885 for (ScheduleBundle *Bundle : Bundles) {
4886 if (ScheduleCopyableDataMap.empty() && TotalOpCount == 0)
4888 SmallPtrSet<Value *, 4> ParentsUniqueUsers;
4891 auto *It =
find(Bundle->getTreeEntry()->Scalars, In);
4892 bool IsNonSchedulableWithParentPhiNode =
4893 Bundle->getTreeEntry()->doesNotNeedToSchedule() &&
4894 Bundle->getTreeEntry()->UserTreeIndex &&
4895 Bundle->getTreeEntry()->UserTreeIndex.UserTE->hasState() &&
4896 Bundle->getTreeEntry()->UserTreeIndex.UserTE->State !=
4897 TreeEntry::SplitVectorize &&
4898 Bundle->getTreeEntry()->UserTreeIndex.UserTE->getOpcode() ==
4902 std::distance(Bundle->getTreeEntry()->Scalars.begin(), It);
4903 assert(Lane >= 0 &&
"Lane not set");
4905 !Bundle->getTreeEntry()->ReorderIndices.empty())
4906 Lane = Bundle->getTreeEntry()->ReorderIndices[Lane];
4907 assert(Lane <
static_cast<int>(
4908 Bundle->getTreeEntry()->Scalars.size()) &&
4909 "Couldn't find extract lane");
4920 In->getNumOperands() ==
4921 Bundle->getTreeEntry()->getNumOperands() ||
4922 (
isa<ZExtInst>(In) && Bundle->getTreeEntry()->getOpcode() ==
4923 Instruction::Select) ||
4924 Bundle->getTreeEntry()->isCopyableElement(In) ||
4925 Bundle->getTreeEntry()->hasReassocScalars()) &&
4926 "Missed TreeEntry operands?");
4932 bool CopyableDepsOnly =
4933 IsNonSchedulableWithParentPhiNode &&
4935 .
insert(Bundle->getTreeEntry()
4936 ->UserTreeIndex.UserTE->Scalars[Lane])
4943 bool IsBlended = Bundle->getTreeEntry()->State ==
4944 TreeEntry::BlendedLoadVectorize;
4945 for (
unsigned OpIdx :
4948 IsBlended ?
In->getOperand(OpIdx)
4949 : Bundle->getTreeEntry()->getOperand(
4951 FoundInOpColumns |= (
I ==
In) && !CopyableDepsOnly;
4955 I, Bundle->getTreeEntry(), OpIdx, Checked,
4956 Bundle->getTreeEntry()->isExpandedOperand(In, OpIdx),
4960 if (Bundle->getTreeEntry()->isCopyableElement(In))
4962 It = std::find(std::next(It),
4963 Bundle->getTreeEntry()->Scalars.end(), In);
4964 }
while (It != Bundle->getTreeEntry()->Scalars.end());
4974 auto UseIt = OperandsUses.
find(In);
4975 if (UseIt != OperandsUses.
end() && UseIt->second > 0) {
4976 --UseIt->getSecond();
4979 if (ScheduleData *OpSD = getScheduleData(In))
4980 DecrUnsched(OpSD,
false);
4989 if (TotalOpCount > 0) {
4998 auto UseIt = OperandsUses.
find(OpI);
4999 if (UseIt == OperandsUses.
end() || UseIt->second == 0)
5001 --UseIt->getSecond();
5003 if (ScheduleData *OpSD = getScheduleData(OpI)) {
5005 <<
"SLP: check for readiness (scalar arg): "
5007 DecrUnsched(OpSD,
false);
5013 for (
const ScheduleBundle *Bundle : Bundles) {
5014 if (TotalOpCount == 0)
5016 TreeEntry *
TE = Bundle->getTreeEntry();
5017 if (!
TE->hasReassocScalars())
5019 for (
Value *V :
TE->getReassocScalars()) {
5023 auto UseIt = OperandsUses.
find(OpI);
5024 if (UseIt == OperandsUses.
end() || UseIt->second == 0)
5027 "(reassociated operand): "
5030 bool ReleasedAsCopyable =
false;
5031 if (!ScheduleCopyableDataMap.empty()) {
5032 for (
const Use &U :
In->operands()) {
5035 for (ScheduleCopyableData *CD :
5036 getScheduleCopyableData(In,
U.getOperandNo(), OpI)) {
5040 if (Checked.
insert(std::make_pair(CD,
U.getOperandNo()))
5042 DecrUnsched(CD,
false);
5050 for (
auto It =
find(
TE->Scalars, In);
5051 It !=
TE->Scalars.end() && !ReleasedAsCopyable;
5054 int Lane = std::distance(
TE->Scalars.begin(), It);
5056 ReleasedAsCopyable |=
5057 TE->getOperand(OpIdx)[Lane] == OpI &&
5058 getScheduleCopyableData(EdgeInfo(TE, OpIdx), OpI);
5061 if (!ReleasedAsCopyable) {
5062 if (ScheduleData *OpSD = getScheduleData(OpI))
5063 for (
unsigned I = 0,
E = UseIt->second;
I !=
E; ++
I)
5064 DecrUnsched(OpSD,
false);
5066 TotalOpCount -= UseIt->second;
5074 for (Use &U : BundleMember->getInst()->operands()) {
5077 <<
"SLP: check for readiness (def): " << *
I <<
"\n");
5078 DecrUnschedForInst(BundleMember->getInst(),
U.getOperandNo(),
I);
5086 SmallPtrSet<const ScheduleData *, 4> VisitedMemory;
5087 for (ScheduleData *MemoryDep : SD->getMemoryDependencies()) {
5088 if (!VisitedMemory.
insert(MemoryDep).second)
5093 << *MemoryDep <<
"\n");
5094 DecrUnsched(MemoryDep);
5097 SmallPtrSet<const ScheduleData *, 4> VisitedControl;
5098 for (ScheduleData *Dep : SD->getControlDependencies()) {
5099 if (!VisitedControl.
insert(Dep).second)
5104 <<
"SLP: check for readiness (ctrl): " << *Dep <<
"\n");
5105 DecrUnsched(Dep,
true);
5109 SD->setScheduled(
true);
5115 if (!Entries.
empty()) {
5116 for (TreeEntry *TE : Entries) {
5118 In->getNumOperands() !=
TE->getNumOperands() &&
5119 !
TE->hasReassocScalars())
5122 PseudoBundles.
emplace_back(std::make_unique<ScheduleBundle>());
5123 BundlePtr->setTreeEntry(TE);
5128 ProcessBundleMember(SD, Bundles);
5131 Bundle.setScheduled(
true);
5133 auto AreAllBundlesScheduled =
5134 [&](
const ScheduleEntity *SD,
5138 return !SDBundles.empty() &&
5139 all_of(SDBundles, [&](
const ScheduleBundle *SDBundle) {
5140 return SDBundle->isScheduled();
5143 for (ScheduleEntity *SD : Bundle.getBundle()) {
5146 SDBundles = getScheduleBundles(SD->getInst());
5147 if (!AreAllBundlesScheduled(SD, SDBundles))
5149 SD->setScheduled(
true);
5164 (ScheduleCopyableDataMap.empty() &&
5165 none_of(
R.getTreeEntries(In), [&](
const TreeEntry *TE) {
5166 return TE->isExpandedBinOp(In);
5175 for (TreeEntry *TE :
R.getTreeEntries(In)) {
5176 if (
TE->isCopyableElement(In))
5179 In->getNumOperands() !=
TE->getNumOperands() &&
5180 !
TE->hasReassocScalars())
5182 if (
any_of(SDBundles, [&](
const ScheduleBundle *SDBundle) {
5183 return SDBundle->getTreeEntry() ==
TE;
5186 ScheduleBundle &PseudoBundle =
5187 *PseudoBundles.
emplace_back(std::make_unique<ScheduleBundle>());
5188 PseudoBundle.setTreeEntry(TE);
5189 PseudoBundle.add(SD);
5190 AllBundles.push_back(&PseudoBundle);
5192 ProcessBundleMember(SD, AllBundles);
5202 assert(ScheduleStart->getParent() == ScheduleEnd->getParent() &&
5203 ScheduleStart->comesBefore(ScheduleEnd) &&
5204 "Not a valid scheduling region?");
5206 for (
auto *
I = ScheduleStart;
I != ScheduleEnd;
I =
I->getNextNode()) {
5208 if (!Bundles.
empty()) {
5209 for (ScheduleBundle *Bundle : Bundles) {
5210 assert(isInSchedulingRegion(*Bundle) &&
5211 "primary schedule data not in window?");
5216 auto *SD = getScheduleData(
I);
5219 assert(isInSchedulingRegion(*SD) &&
5220 "primary schedule data not in window?");
5225 [](
const ScheduleEntity *Bundle) {
5226 return Bundle->isReady();
5228 "item in ready list not ready?");
5232 template <
typename ReadyListType>
5233 void initialFillReadyList(ReadyListType &ReadyList) {
5234 SmallPtrSet<ScheduleBundle *, 16> Visited;
5235 for (
auto *
I = ScheduleStart;
I != ScheduleEnd;
I =
I->getNextNode()) {
5236 ScheduleData *SD = getScheduleData(
I);
5237 if (SD && SD->hasValidDependencies() && SD->isReady()) {
5240 for (ScheduleBundle *Bundle : Bundles) {
5241 if (!Visited.
insert(Bundle).second)
5243 if (Bundle->hasValidDependencies() && Bundle->isReady()) {
5244 ReadyList.insert(Bundle);
5246 << *Bundle <<
"\n");
5251 ReadyList.insert(SD);
5253 <<
"SLP: initially in ready list: " << *SD <<
"\n");
5264 const InstructionsState &S,
const EdgeInfo &EI);
5271 std::optional<ScheduleBundle *>
5273 const InstructionsState &S,
const EdgeInfo &EI);
5276 ScheduleData *allocateScheduleDataChunks();
5280 bool extendSchedulingRegion(
Value *V,
const InstructionsState &S);
5284 void initScheduleData(Instruction *FromI, Instruction *ToI,
5285 ScheduleData *PrevLoadStore,
5286 ScheduleData *NextLoadStore);
5290 void calculateDependencies(ScheduleBundle &Bundle,
bool InsertInReadyList,
5292 const SmallPtrSetImpl<Value *> &ExpandedOps,
5296 void resetSchedule();
5313 SmallDenseMap<Instruction *, ScheduleData *> ScheduleDataMap;
5317 SmallDenseMap<std::pair<EdgeInfo, const Value *>,
5318 std::unique_ptr<ScheduleCopyableData>>
5319 ScheduleCopyableDataMap;
5325 SmallDenseMap<const Instruction *, SmallVector<ScheduleCopyableData *>>
5326 ScheduleCopyableDataMapByInst;
5332 SmallDenseMap<std::pair<std::pair<const Value *, unsigned>,
const Value *>,
5334 ScheduleCopyableDataMapByInstUser;
5354 SmallSetVector<ScheduleCopyableData *, 4>>
5355 ScheduleCopyableDataMapByUsers;
5358 SmallDenseMap<Instruction *, SmallVector<ScheduleBundle *>>
5364 SetVector<ScheduleEntity *> ReadyInsts;
5374 ScheduleData *FirstLoadStoreInRegion =
nullptr;
5378 ScheduleData *LastLoadStoreInRegion =
nullptr;
5383 bool RegionHasStackSave =
false;
5386 int ScheduleRegionSize = 0;
5401 SmallSetVector<ScheduleData *, 8> RecalcCopyableOperandDeps;
5405 SmallDenseSet<std::pair<Instruction *, Instruction *>, 8> IgnoredMemDeps;
5411 int SchedulingRegionID = 1;
5415 MapVector<BasicBlock *, std::unique_ptr<BlockScheduling>> BlocksSchedules;
5419 void scheduleBlock(
const BoUpSLP &R, BlockScheduling *BS);
5422 const SmallDenseSet<Value *> *UserIgnoreList =
nullptr;
5426 SmallPtrSet<Value *, 4> NarrowedChainInsts;
5430 struct OrdersTypeDenseMapInfo {
5431 static unsigned getHashValue(
const OrdersType &V) {
5442 ScalarEvolution *SE;
5443 TargetTransformInfo *TTI;
5444 TargetLibraryInfo *TLI;
5447 AssumptionCache *AC;
5449 const DataLayout *DL;
5450 OptimizationRemarkEmitter *ORE;
5455 unsigned MaxVecRegSize;
5456 unsigned MinVecRegSize;
5459 IRBuilder<TargetFolder> Builder;
5466 DenseMap<const TreeEntry *, std::pair<uint64_t, bool>> MinBWs;
5471 unsigned ReductionBitWidth = 0;
5474 unsigned BaseGraphSize = 1;
5478 std::optional<std::pair<unsigned, unsigned>> CastMaxMinBWSizes;
5482 DenseSet<unsigned> ExtraBitWidthNodes;
5490 SecondInfo::getHashValue(Val.
EdgeIdx));
5511 ChildIteratorType, SmallVector<BoUpSLP::EdgeInfo, 1>::iterator> {
5524 return {&
N->UserTreeIndex,
N->Container};
5528 return {&
N->UserTreeIndex + 1,
N->Container};
5555 static unsigned size(
BoUpSLP *R) {
return R->VectorizableTree.size(); }
5567 OS << Entry->Idx <<
".\n";
5570 for (
auto *V : Entry->Scalars) {
5572 if (
llvm::any_of(R->ExternalUses, [&](
const BoUpSLP::ExternalUser &EU) {
5573 return EU.Scalar == V;
5583 if (Entry->isGather())
5585 if (Entry->State == TreeEntry::ScatterVectorize ||
5586 Entry->State == TreeEntry::StridedVectorize ||
5587 Entry->State == TreeEntry::ExpandVectorize ||
5588 Entry->State == TreeEntry::CompressVectorize ||
5589 Entry->State == TreeEntry::BlendedLoadVectorize)
5590 return "color=blue";
5597 for (
auto *
I : DeletedInstructions) {
5598 if (!
I->getParent()) {
5603 I->insertBefore(F->getEntryBlock(),
5604 F->getEntryBlock().getFirstNonPHIIt());
5606 I->insertBefore(F->getEntryBlock().getTerminator()->getIterator());
5609 for (
Use &U :
I->operands()) {
5611 if (
Op && !DeletedInstructions.count(
Op) &&
Op->hasOneUser() &&
5615 I->dropAllReferences();
5617 for (
auto *
I : DeletedInstructions) {
5619 "trying to erase instruction with users.");
5620 I->eraseFromParent();
5626#ifdef EXPENSIVE_CHECKS
5637 assert(!Mask.empty() && Reuses.
size() == Mask.size() &&
5638 "Expected non-empty mask.");
5641 for (
unsigned I = 0,
E = Prev.
size();
I <
E; ++
I)
5643 Reuses[Mask[
I]] = Prev[
I];
5651 bool BottomOrder =
false) {
5652 assert(!Mask.empty() &&
"Expected non-empty mask.");
5653 unsigned Sz = Mask.size();
5656 if (Order.
empty()) {
5658 std::iota(PrevOrder.
begin(), PrevOrder.
end(), 0);
5660 PrevOrder.
swap(Order);
5663 for (
unsigned I = 0;
I < Sz; ++
I)
5665 Order[
I] = PrevOrder[Mask[
I]];
5667 return Data.value() == Sz ||
Data.index() ==
Data.value();
5676 if (Order.
empty()) {
5678 std::iota(MaskOrder.
begin(), MaskOrder.
end(), 0);
5688 for (
unsigned I = 0;
I < Sz; ++
I)
5690 Order[MaskOrder[
I]] =
I;
5694std::optional<BoUpSLP::OrdersType>
5696 bool TopToBottom,
bool IgnoreReorder) {
5697 assert(TE.isGather() &&
"Expected gather node only.");
5701 Type *ScalarTy = GatheredScalars.
front()->getType();
5702 size_t NumScalars = GatheredScalars.
size();
5704 return std::nullopt;
5711 tryToGatherExtractElements(GatheredScalars, ExtractMask, NumParts);
5713 isGatherShuffledEntry(&TE, GatheredScalars, Mask, Entries, NumParts,
5716 if (GatherShuffles.
empty() && ExtractShuffles.
empty())
5717 return std::nullopt;
5718 OrdersType CurrentOrder(NumScalars, NumScalars);
5719 if (GatherShuffles.
size() == 1 &&
5721 Entries.
front().front()->isSame(TE.Scalars)) {
5725 return std::nullopt;
5727 if (Entries.
front().front()->UserTreeIndex.UserTE ==
5728 TE.UserTreeIndex.UserTE)
5729 return std::nullopt;
5732 if (!IgnoreReorder && Entries.
front().front()->Idx == 0)
5733 return std::nullopt;
5736 if (!Entries.
front().front()->ReuseShuffleIndices.empty() &&
5737 TE.getVectorFactor() == 2 && Mask.size() == 2 &&
5740 return P.value() % 2 != static_cast<int>(P.index()) % 2;
5742 return std::nullopt;
5746 std::iota(CurrentOrder.
begin(), CurrentOrder.
end(), 0);
5747 return CurrentOrder;
5751 return all_of(Mask, [&](
int I) {
5758 if ((ExtractShuffles.
empty() && IsSplatMask(Mask) &&
5759 (Entries.
size() != 1 ||
5760 Entries.
front().front()->ReorderIndices.empty())) ||
5761 (GatherShuffles.
empty() && IsSplatMask(ExtractMask)))
5762 return std::nullopt;
5768 if (ShuffledSubMasks.
test(
I))
5770 const int VF = GetVF(
I);
5778 ShuffledSubMasks.
set(
I);
5782 int FirstMin = INT_MAX;
5783 int SecondVecFound =
false;
5785 int Idx = Mask[
I * PartSz + K];
5787 Value *V = GatheredScalars[
I * PartSz + K];
5789 SecondVecFound =
true;
5798 SecondVecFound =
true;
5802 FirstMin = (FirstMin / PartSz) * PartSz;
5804 if (SecondVecFound) {
5806 ShuffledSubMasks.
set(
I);
5810 int Idx = Mask[
I * PartSz + K];
5814 if (Idx >= PartSz) {
5817 SecondVecFound =
true;
5823 if (
static_cast<unsigned>(
I * PartSz + Idx) >= CurrentOrder.
size())
5825 if (CurrentOrder[
I * PartSz + Idx] >
5826 static_cast<unsigned>(
I * PartSz + K) &&
5827 CurrentOrder[
I * PartSz + Idx] !=
5828 static_cast<unsigned>(
I * PartSz + Idx))
5829 CurrentOrder[
I * PartSz + Idx] =
I * PartSz + K;
5832 if (SecondVecFound) {
5834 ShuffledSubMasks.
set(
I);
5840 if (!ExtractShuffles.
empty())
5841 TransformMaskToOrder(
5842 CurrentOrder, ExtractMask, PartSz, NumParts, [&](
unsigned I) {
5843 if (
I >= ExtractShuffles.
size() || !ExtractShuffles[
I])
5846 unsigned Sz =
getNumElems(TE.getVectorFactor(), PartSz,
I);
5848 int K =
I * PartSz + Idx;
5849 if (
static_cast<unsigned>(K) >= ExtractMask.
size())
5853 if (!TE.ReuseShuffleIndices.empty())
5854 K = TE.ReuseShuffleIndices[K];
5857 if (!TE.ReorderIndices.empty())
5858 K = std::distance(TE.ReorderIndices.begin(),
5859 find(TE.ReorderIndices, K));
5863 VF = std::max(VF, EI->getVectorOperandType()
5865 .getKnownMinValue());
5870 if (GatherShuffles.
size() == 1 && NumParts != 1) {
5871 if (ShuffledSubMasks.
any())
5872 return std::nullopt;
5873 PartSz = NumScalars;
5876 if (!Entries.
empty())
5877 TransformMaskToOrder(CurrentOrder, Mask, PartSz, NumParts, [&](
unsigned I) {
5878 if (
I >= GatherShuffles.
size() || !GatherShuffles[
I])
5880 return std::max(Entries[
I].front()->getVectorFactor(),
5881 Entries[
I].back()->getVectorFactor());
5883 unsigned NumUndefs =
count(CurrentOrder, NumScalars);
5884 if (ShuffledSubMasks.
all() || (NumScalars > 2 && NumUndefs >= NumScalars / 2))
5885 return std::nullopt;
5886 return std::move(CurrentOrder);
5891 bool CompareOpcodes =
true) {
5897 return (!GEP1 || GEP1->getNumOperands() == 2) &&
5898 (!GEP2 || GEP2->getNumOperands() == 2) &&
5899 (((!GEP1 ||
isConstant(GEP1->getOperand(1))) &&
5900 (!GEP2 ||
isConstant(GEP2->getOperand(1)))) ||
5903 getSameOpcode({GEP1->getOperand(1), GEP2->getOperand(1)}, TLI)));
5907template <
typename T>
5912 return CommonAlignment;
5918 "Order is empty. Please check it before using isReverseOrder.");
5919 unsigned Sz = Order.
size();
5921 return Pair.value() == Sz || Sz - Pair.index() - 1 == Pair.value();
5940 const SCEV *PtrSCEVLowest =
nullptr;
5941 const SCEV *PtrSCEVHighest =
nullptr;
5944 for (
Value *Ptr : PointerOps) {
5949 if (!PtrSCEVLowest && !PtrSCEVHighest) {
5950 PtrSCEVLowest = PtrSCEVHighest = PtrSCEV;
5957 PtrSCEVLowest = PtrSCEV;
5964 PtrSCEVHighest = PtrSCEV;
5972 int Size =
DL.getTypeStoreSize(ElemTy);
5973 auto TryGetStride = [&](
const SCEV *Dist,
5974 const SCEV *Multiplier) ->
const SCEV * {
5976 if (M->getOperand(0) == Multiplier)
5977 return M->getOperand(1);
5978 if (M->getOperand(1) == Multiplier)
5979 return M->getOperand(0);
5982 if (Multiplier == Dist)
5987 const SCEV *Stride =
nullptr;
5988 if (
Size != 1 || SCEVs.
size() > 1) {
5990 Stride = TryGetStride(Dist, Sz);
5998 using DistOrdPair = std::pair<int64_t, int>;
6000 std::set<DistOrdPair,
decltype(Compare)> Offsets(Compare);
6001 bool IsConsecutive =
true;
6002 for (
const auto [Idx, PtrSCEV] :
enumerate(SCEVs)) {
6004 if (PtrSCEV != PtrSCEVLowest) {
6006 const SCEV *Coeff = TryGetStride(Diff, Stride);
6016 Dist = SC->getAPInt().getZExtValue();
6021 auto Res = Offsets.emplace(Dist, Idx);
6025 IsConsecutive = IsConsecutive && std::next(Res.first) == Offsets.end();
6027 SortedIndices.
clear();
6028 if (!IsConsecutive) {
6031 for (
const auto [Idx, Pair] :
enumerate(Offsets))
6032 SortedIndices[Idx] = Pair.second;
6050 auto *Begin = std::next(
Mask.begin(), Index);
6051 std::iota(Begin, std::next(Begin, SubVecVF), 0);
6052 Vec = Builder.CreateShuffleVector(V, Mask);
6055 std::iota(
Mask.begin(),
Mask.end(), 0);
6056 std::iota(std::next(
Mask.begin(), Index),
6057 std::next(
Mask.begin(), Index + SubVecVF), VecVF);
6059 return Generator(Vec, V, Mask);
6062 std::iota(ResizeMask.begin(), std::next(ResizeMask.begin(), SubVecVF), 0);
6063 V = Builder.CreateShuffleVector(V, ResizeMask);
6065 return Builder.CreateShuffleVector(Vec, V, Mask);
6070 unsigned SubVecVF,
unsigned Index) {
6072 std::iota(Mask.begin(), Mask.end(), Index);
6073 return Builder.CreateShuffleVector(Vec, Mask);
6083 const unsigned Sz = PointerOps.
size();
6086 CompressMask[0] = 0;
6088 std::optional<unsigned> Stride = 0;
6091 Value *Ptr = Order.
empty() ? PointerOps[
I] : PointerOps[Order[
I]];
6092 std::optional<int64_t> OptPos =
6094 if (!OptPos || OptPos > std::numeric_limits<unsigned>::max())
6096 unsigned Pos =
static_cast<unsigned>(*OptPos);
6097 CompressMask[
I] = Pos;
6104 if (Pos != *Stride *
I)
6107 return Stride.has_value();
6121 InterleaveFactor = 0;
6123 const size_t Sz = VL.
size();
6130 if (AreAllUsersVectorized(V))
6133 TTI.getVectorInstrCost(Instruction::ExtractElement, VecTy,
CostKind,
6134 Mask.empty() ?
I : Mask[
I]);
6137 if (ExtractCost <= ScalarCost)
6142 if (Order.
empty()) {
6143 Ptr0 = PointerOps.
front();
6144 PtrN = PointerOps.
back();
6146 Ptr0 = PointerOps[Order.
front()];
6147 PtrN = PointerOps[Order.
back()];
6149 std::optional<int64_t> Diff =
6153 const size_t MaxRegSize =
6157 if (*Diff / Sz >= MaxRegSize / 8)
6161 Align CommonAlignment = LI->getAlign();
6166 if (IsMasked && !
TTI.isLegalMaskedLoad(LoadVecTy, CommonAlignment,
6167 LI->getPointerAddressSpace()))
6173 assert(CompressMask.
size() >= 2 &&
"At least two elements are required");
6177 auto [ScalarGEPCost, VectorGEPCost] =
6179 Instruction::Load,
CostKind, ScalarTy, LoadVecTy);
6196 LoadCost =
TTI.getMemIntrinsicInstrCost(
6199 LI->getPointerAddressSpace()),
6203 TTI.getMemoryOpCost(Instruction::Load, LoadVecTy, CommonAlignment,
6204 LI->getPointerAddressSpace(),
CostKind);
6206 if (IsStrided && !IsMasked && Order.
empty()) {
6214 AlignedLoadVecTy = LoadVecTy;
6215 if (
TTI.isLegalInterleavedAccessType(AlignedLoadVecTy, CompressMask[1],
6217 LI->getPointerAddressSpace())) {
6219 VectorGEPCost +
TTI.getInterleavedMemoryOpCost(
6220 Instruction::Load, AlignedLoadVecTy,
6221 CompressMask[1], {}, CommonAlignment,
6222 LI->getPointerAddressSpace(),
CostKind, IsMasked);
6223 if (InterleavedCost < GatherCost) {
6224 InterleaveFactor = CompressMask[1];
6225 LoadVecTy = AlignedLoadVecTy;
6236 if (VectorGEPCost + LoadCost >= GatherCost)
6240 if (!Order.
empty()) {
6243 NewMask[
I] = CompressMask[Mask[
I]];
6245 CompressMask.
swap(NewMask);
6247 InstructionCost TotalVecCost = VectorGEPCost + LoadCost + CompressCost;
6248 return TotalVecCost < GatherCost;
6262 unsigned InterleaveFactor;
6266 CostKind, AreAllUsersVectorized, IsMasked,
6267 InterleaveFactor, CompressMask, LoadVecTy);
6280 const size_t Sz = VL.
size();
6286 std::optional<int64_t> Diff =
6288 if (!Diff || *Diff <= 0)
6291 const unsigned MaxRegSize =
6294 const unsigned ScalarBits =
DL.getTypeSizeInBits(ScalarTy).getFixedValue();
6295 if (ScalarBits == 0 ||
6296 static_cast<uint64_t>(*Diff) / Sz >= MaxRegSize / ScalarBits)
6300 if (!
TTI.isLegalMaskedStore(StoreVecTy, CommonAlignment, AS,
6308 Value *Ptr = Order.
empty() ? PointerOps[
I] : PointerOps[Order[
I]];
6309 std::optional<int64_t> Off =
6311 if (!Off || *Off <= Prev || *Off > *Diff)
6313 ReuseShuffleIndices[*Off] =
static_cast<int>(
I);
6333 Align Alignment,
const int64_t Diff,
6334 const size_t Sz)
const {
6335 if (Diff % (Sz - 1) != 0)
6339 auto IsAnyPointerUsedOutGraph =
any_of(PointerOps, [&](
Value *V) {
6341 return !isVectorized(U) && !MustGather.contains(U);
6345 const uint64_t AbsoluteDiff = std::abs(Diff);
6347 if (IsAnyPointerUsedOutGraph ||
6348 (AbsoluteDiff > Sz &&
6352 Diff == -(
static_cast<int64_t
>(Sz) - 1)) {
6353 int64_t Stride = Diff /
static_cast<int64_t
>(Sz - 1);
6354 if (Diff != Stride *
static_cast<int64_t
>(Sz - 1))
6356 if (!TTI->isLegalStridedLoadStore(VecTy, Alignment))
6367 const size_t Sz = PointerOps.
size();
6375 SortedIndices.
empty() ? PointerOps[
I] : PointerOps[SortedIndices[
I]];
6376 std::optional<int64_t>
Offset =
6378 assert(
Offset &&
"sortPtrAccesses should have validated this pointer");
6379 SortedOffsetsFromBase[
I] = *
Offset;
6396 int64_t StrideWithinGroup =
6397 SortedOffsetsFromBase[1] - SortedOffsetsFromBase[0];
6400 auto IsEndOfGroupIndex = [=, &SortedOffsetsFromBase](
unsigned Idx) {
6401 return SortedOffsetsFromBase[Idx] - SortedOffsetsFromBase[Idx - 1] !=
6406 unsigned GroupSize = FoundIt != Indices.end() ? *FoundIt : Sz;
6408 unsigned VecSz = Sz;
6409 Type *NewScalarTy = ScalarTy;
6413 bool NeedsWidening = Sz != GroupSize;
6414 const uint64_t UnitBitWidth = DL->getTypeSizeInBits(ScalarTy).getFixedValue();
6415 if (NeedsWidening) {
6416 if (Sz % GroupSize != 0)
6419 if (StrideWithinGroup != 1)
6421 VecSz = Sz / GroupSize;
6422 NewScalarTy =
Type::getIntNTy(SE->getContext(), UnitBitWidth * GroupSize);
6427 if (!
isStridedLoad(PointerOps, NewScalarTy, Alignment, Diff, VecSz))
6430 int64_t StrideIntVal = StrideWithinGroup;
6431 if (NeedsWidening) {
6434 unsigned CurrentGroupStartIdx = GroupSize;
6435 int64_t StrideBetweenGroups =
6436 SortedOffsetsFromBase[GroupSize] - SortedOffsetsFromBase[0];
6437 StrideIntVal = StrideBetweenGroups;
6438 for (; CurrentGroupStartIdx < Sz; CurrentGroupStartIdx += GroupSize) {
6439 if (SortedOffsetsFromBase[CurrentGroupStartIdx] -
6440 SortedOffsetsFromBase[CurrentGroupStartIdx - GroupSize] !=
6441 StrideBetweenGroups)
6445 auto CheckGroup = [=](
const unsigned StartIdx) ->
bool {
6448 unsigned GroupEndIdx = FoundIt != Indices.end() ? *FoundIt : Sz;
6449 return GroupEndIdx - StartIdx == GroupSize;
6451 for (
unsigned I = 0;
I < Sz;
I += GroupSize) {
6457 Type *StrideTy = DL->getIndexType(Ptr0->
getType());
6467 bool IsLoad)
const {
6468 const unsigned Sz = PointerOps.
size();
6469 const unsigned MinProfitableStridedOps =
6477 Type *NewScalarTy = BaseTy;
6481 DL->getTypeSizeInBits(BaseTy).getFixedValue() * NumOffsets);
6486 return StridedTy && TTI->isTypeLegal(StridedTy) &&
6487 TTI->isLegalStridedLoadStore(StridedTy, CommonAlignment);
6493 return Sz % NumOffsets == 0 &&
6494 IsLegalStridedTy(GetStridedTy(NumOffsets));
6503 OffsetToPointerOpIdxMap;
6509 for (
auto [Idx, Ptr] :
enumerate(PointerOps)) {
6510 const SCEV *PtrSCEV = SE->getSCEV(Ptr);
6516 const SCEV *StrideMultiple = PtrSCEV;
6523 Offset = SC->getAPInt().getSExtValue();
6524 if (
Offset >= std::numeric_limits<int64_t>::max() - 1) {
6528 StrideMultiple = SE->getMinusSCEV(StrideMultiple, SC);
6532 OffsetToPointerOpIdxMap[
Offset].first.push_back(Ptr);
6533 OffsetToPointerOpIdxMap[
Offset].second.push_back(Idx);
6534 StrideMultiples.
insert(StrideMultiple);
6536 unsigned NumOffsets = OffsetToPointerOpIdxMap.
size();
6540 unsigned VecSz = Sz;
6541 if (NumOffsets > 1) {
6542 if (Sz % NumOffsets != 0)
6544 VecSz = Sz / NumOffsets;
6547 if (StrideMultiples.
size() != VecSz)
6550 auto *StridedLoadTy = GetStridedTy(NumOffsets);
6551 if (!IsLegalStridedTy(StridedLoadTy))
6557 for (
auto [Idx, MapPair] :
enumerate(OffsetToPointerOpIdxMap)) {
6558 if (MapPair.second.first.size() != VecSz)
6560 SortedOffsetsV[Idx] = MapPair.first;
6562 sort(SortedOffsetsV);
6564 if (NumOffsets > 1) {
6565 int64_t BaseBytes = DL->getTypeStoreSize(BaseTy);
6567 if (SortedOffsetsV[
I] - SortedOffsetsV[
I - 1] != BaseBytes)
6636 auto UpdateSortedIndices =
6639 if (SortedIndicesForOffset.
empty()) {
6640 SortedIndicesForOffset.
resize(IndicesInAllPointerOps.
size());
6641 std::iota(SortedIndicesForOffset.
begin(),
6642 SortedIndicesForOffset.
end(), 0);
6644 for (
const auto [Num, Idx] :
enumerate(SortedIndicesForOffset)) {
6645 SortedIndicesDraft[Num * NumOffsets + OffsetNum] =
6646 IndicesInAllPointerOps[Idx];
6650 int64_t LowestOffset = SortedOffsetsV[0];
6654 const SCEV *Stride0 =
6660 OffsetToPointerOpIdxMap[LowestOffset].second;
6661 UpdateSortedIndices(SortedIndicesForOffset0, IndicesInAllPointerOps0, 0);
6666 for (
int J :
seq<int>(1, NumOffsets)) {
6667 SortedIndicesForOffset.
clear();
6669 int64_t
Offset = SortedOffsetsV[J];
6671 OffsetToPointerOpIdxMap[
Offset].first;
6673 OffsetToPointerOpIdxMap[
Offset].second;
6675 PointerOpsForOffset, BaseTy, *DL, *SE, SortedIndicesForOffset);
6677 if (!StrideWithinGroup || StrideWithinGroup != Stride0)
6680 UpdateSortedIndices(SortedIndicesForOffset, IndicesInAllPointerOps, J);
6683 SortedIndices.
clear();
6684 SortedIndices = std::move(SortedIndicesDraft);
6686 SPtrInfo.
Ty = StridedLoadTy;
6693 unsigned *BestVF,
bool TryRecursiveCheck)
const {
6706 if (DL->getTypeSizeInBits(ScalarTy) != DL->getTypeAllocSizeInBits(ScalarTy))
6712 const size_t Sz = VL.
size();
6714 auto *POIter = PointerOps.
begin();
6715 for (
Value *V : VL) {
6717 if (!L || !L->isSimple())
6719 *POIter = L->getPointerOperand();
6725 bool IsSorted =
sortPtrAccesses(PointerOps, ScalarTy, *DL, *SE, Order);
6734 std::optional<bool> MaskedGatherLegal;
6735 auto IsMaskedGatherLegal = [&] {
6736 if (!MaskedGatherLegal)
6738 TTI->isLegalMaskedGather(VecTy, CommonAlignment) &&
6739 !TTI->forceScalarizeMaskedGather(VecTy, CommonAlignment);
6740 return *MaskedGatherLegal;
6749 Value *TrueBase =
nullptr;
6750 Value *FalseBase =
nullptr;
6754 TTI->isLegalMaskedLoad(VecTy, CommonAlignment,
6762 if (!IsMaskedGatherLegal())
6773 if (Order.
empty()) {
6774 Ptr0 = PointerOps.
front();
6775 PtrN = PointerOps.
back();
6777 Ptr0 = PointerOps[Order.
front()];
6778 PtrN = PointerOps[Order.
back()];
6783 std::optional<int64_t> Diff0 =
6785 std::optional<int64_t> DiffN =
6788 "sortPtrAccesses should have validated these pointers");
6789 int64_t Diff = *DiffN - *Diff0;
6791 if (
static_cast<uint64_t
>(Diff) == Sz - 1)
6794 *TLI, CostKind, [&](
Value *V) {
6795 return areAllUsersVectorized(
6803 Diff, Ptr0, SPtrInfo))
6806 if (!IsMaskedGatherLegal())
6811 auto CheckForShuffledLoads = [&, &TTI = *TTI](
Align CommonAlignment,
6813 bool ProfitableGatherPointers) {
6817 auto [ScalarGEPCost, VectorGEPCost] =
6819 CostKind, ScalarTy, VecTy);
6823 Type *PtrScalarTy = PointerOps.
front()->getType()->getScalarType();
6829 if (
static_cast<unsigned>(
count_if(
6834 TTI,
SLPReVec, PtrScalarTy, PtrVecTy, DemandedElts,
true,
6840 true,
false, CostKind) +
6852 TTI.getMemIntrinsicInstrCost(
6855 false, CommonAlignment),
6857 (ProfitableGatherPointers ? 0 : VectorGEPCost);
6865 constexpr unsigned ListLimit = 4;
6866 if (!TryRecursiveCheck || VL.
size() < ListLimit)
6869 unsigned Sz = DL->getTypeSizeInBits(ScalarTy);
6877 TTI, ScalarTy, VF - 1,
SLPReVec)) {
6879 for (
unsigned Cnt = 0, End = VL.
size(); Cnt < End; Cnt += VF) {
6880 const unsigned SliceVF = std::min(VF, End - Cnt);
6885 PointerOps, SPtrInfo, BestVF,
6893 DemandedElts.
setBits(Cnt, Cnt + SliceVF);
6909 if (!DemandedElts.
isZero()) {
6916 if (DemandedElts[Idx])
6920 for (
const auto &[SliceStart, LS] : States) {
6921 const unsigned SliceVF = std::min<unsigned>(VF, VL.
size() - SliceStart);
6928 ArrayRef(PointerOps).slice(SliceStart, SliceVF),
6929 LI0->getPointerOperand(), Instruction::Load,
6930 CostKind, ScalarTy, SubVecTy)
6933 if (
static_cast<unsigned>(
6935 PointerOps.
size() - 1 ||
6941 true,
false, CostKind);
6953 TTI.getMemoryOpCost(Instruction::Load, SubVecTy, LI0->getAlign(),
6954 LI0->getPointerAddressSpace(), CostKind,
6959 VecLdCost += TTI.getMemIntrinsicInstrCost(
6961 Intrinsic::experimental_vp_strided_load,
6962 SubVecTy, LI0->getPointerOperand(),
6963 false, CommonAlignment),
6969 TTI.getMemIntrinsicInstrCost(
6972 LI0->getPointerAddressSpace()),
6977 VecLdCost += TTI.getMemIntrinsicInstrCost(
6979 Intrinsic::masked_gather, SubVecTy,
6980 LI0->getPointerOperand(),
6981 false, CommonAlignment),
6990 LI0->getPointerAddressSpace(), CostKind);
6996 const unsigned SliceIdx = SliceStart / VF;
6998 ShuffleMask[Idx] = Idx / VF == SliceIdx ? VL.
size() + Idx % VF : Idx;
7002 ShuffleMask, SliceStart, SubVecTy);
7007 if (MaskedGatherCost >= VecLdCost &&
7020 bool ProfitableGatherPointers =
7021 L && Sz > 2 &&
static_cast<unsigned>(
count_if(PointerOps, [L](
Value *V) {
7022 return L->isLoopInvariant(V);
7024 if (ProfitableGatherPointers ||
all_of(PointerOps, [](
Value *
P) {
7027 (
GEP &&
GEP->getNumOperands() == 2 &&
7035 if (!TryRecursiveCheck || !CheckForShuffledLoads(CommonAlignment, BestVF,
7036 ProfitableGatherPointers))
7048 all_of(VL, [](
const Value *V) {
return V->getType()->isPointerTy(); }) &&
7049 "Expected list of pointer operands.");
7054 std::pair<BasicBlock *, Value *>,
7058 .try_emplace(std::make_pair(
7062 SortedIndices.
clear();
7064 auto Key = std::make_pair(BBs[Cnt + 1],
7066 bool Found =
any_of(Bases.try_emplace(
Key).first->second,
7067 [&, &Cnt = Cnt, &Ptr = Ptr](
auto &
Base) {
7068 std::optional<int64_t> Diff =
7069 getPointersDiff(ElemTy, std::get<0>(Base.front()),
7070 ElemTy, Ptr, DL, SE,
7075 Base.emplace_back(Ptr, *Diff, Cnt + 1);
7081 if (Bases.size() > VL.
size() / 2 - 1)
7085 Bases.find(
Key)->second.emplace_back().emplace_back(Ptr, 0, Cnt + 1);
7089 if (Bases.size() == VL.
size())
7092 if (Bases.size() == 1 && (Bases.front().second.size() == 1 ||
7093 Bases.front().second.size() == VL.
size()))
7098 auto ComparePointers = [](
Value *Ptr1,
Value *Ptr2) {
7107 FirstPointers.
insert(P1);
7108 SecondPointers.
insert(P2);
7114 "Unable to find matching root.");
7117 for (
auto &
Base : Bases) {
7118 for (
auto &Vec :
Base.second) {
7119 if (Vec.size() > 1) {
7121 int64_t InitialOffset = std::get<1>(Vec[0]);
7122 bool AnyConsecutive =
7124 return std::get<1>(
P.value()) ==
7125 int64_t(
P.index()) + InitialOffset;
7129 if (!AnyConsecutive)
7134 return ComparePointers(std::get<0>(V1.front()), std::get<0>(V2.front()));
7138 for (
auto &
T : Bases)
7139 for (
const auto &Vec :
T.second)
7140 for (
const auto &
P : Vec)
7144 "Expected SortedIndices to be the size of VL");
7148std::optional<BoUpSLP::OrdersType>
7150 assert(TE.isGather() &&
"Expected gather node only.");
7151 Type *ScalarTy = TE.Scalars[0]->getType();
7154 Ptrs.
reserve(TE.Scalars.size());
7156 BBs.
reserve(TE.Scalars.size());
7157 for (
Value *V : TE.Scalars) {
7159 if (!L || !L->isSimple())
7160 return std::nullopt;
7166 if (!LoadEntriesToVectorize.contains(TE.Idx) &&
7168 return std::move(Order);
7169 return std::nullopt;
7180 if (VU->
getType() != V->getType())
7183 if (!VU->
hasOneUse() && !V->hasOneUse())
7189 if (Idx1 == std::nullopt || Idx2 == std::nullopt)
7195 bool IsReusedIdx =
false;
7197 if (IE2 == VU && !IE1)
7199 if (IE1 == V && !IE2)
7200 return V->hasOneUse();
7201 if (IE1 && IE1 != V) {
7203 IsReusedIdx |= ReusedIdx.
test(Idx1);
7204 ReusedIdx.
set(Idx1);
7205 if ((IE1 != VU && !IE1->
hasOneUse()) || IsReusedIdx)
7210 if (IE2 && IE2 != VU) {
7212 IsReusedIdx |= ReusedIdx.
test(Idx2);
7213 ReusedIdx.
set(Idx2);
7214 if ((IE2 != V && !IE2->hasOneUse()) || IsReusedIdx)
7219 }
while (!IsReusedIdx && (IE1 || IE2));
7223std::optional<BoUpSLP::OrdersType>
7225 bool IgnoreReorder) {
7228 if (!TE.ReuseShuffleIndices.empty()) {
7230 return std::nullopt;
7238 unsigned Sz = TE.Scalars.size();
7239 if (TE.isGather()) {
7240 if (std::optional<OrdersType> CurrentOrder =
7245 addMask(Mask, TE.ReuseShuffleIndices);
7246 OrdersType Res(TE.getVectorFactor(), TE.getVectorFactor());
7247 unsigned Sz = TE.Scalars.size();
7248 for (
int K = 0, E = TE.getVectorFactor() / Sz; K < E; ++K) {
7251 Res[Idx + K * Sz] =
I + K * Sz;
7253 return std::move(Res);
7256 if (Sz == 2 && TE.getVectorFactor() == 4 &&
7260 2 * TE.getVectorFactor()),
7262 return std::nullopt;
7263 if (TE.ReuseShuffleIndices.size() % Sz != 0)
7264 return std::nullopt;
7268 if (TE.ReorderIndices.empty())
7269 std::iota(ReorderMask.
begin(), ReorderMask.
end(), 0);
7272 addMask(ReorderMask, TE.ReuseShuffleIndices);
7273 unsigned VF = ReorderMask.
size();
7277 for (
unsigned I = 0;
I < VF;
I += Sz) {
7279 unsigned UndefCnt = 0;
7280 unsigned Limit = std::min(Sz, VF -
I);
7290 UsedVals.
test(Val) || UndefCnt > Sz / 2)
7291 return std::nullopt;
7293 for (
unsigned K = 0; K < NumParts; ++K) {
7294 unsigned Idx = Val + Sz * K;
7295 if (Idx < VF &&
I + K < VF)
7296 ResOrder[Idx] =
I + K;
7299 return std::move(ResOrder);
7301 unsigned VF = TE.getVectorFactor();
7304 TE.ReuseShuffleIndices.end());
7305 if (TE.hasState() && TE.getOpcode() == Instruction::ExtractElement &&
7306 !TE.hasCopyableElements() &&
all_of(TE.Scalars, [Sz](
Value *V) {
7307 if (isa<PoisonValue>(V))
7309 std::optional<unsigned> Idx = getExtractIndex(cast<Instruction>(V));
7310 return Idx && *Idx < Sz;
7312 assert(!TE.isAltShuffle() &&
"Alternate instructions are only supported "
7313 "by BinaryOperator and CastInst.");
7315 if (TE.ReorderIndices.empty())
7316 std::iota(ReorderMask.
begin(), ReorderMask.
end(), 0);
7319 for (
unsigned I = 0;
I < VF; ++
I) {
7320 int &Idx = ReusedMask[
I];
7323 Value *V = TE.Scalars[ReorderMask[Idx]];
7325 Idx = std::distance(ReorderMask.
begin(),
find(ReorderMask, *EI));
7331 std::iota(ResOrder.
begin(), ResOrder.
end(), 0);
7332 auto *It = ResOrder.
begin();
7333 for (
unsigned K = 0; K < VF; K += Sz) {
7337 std::iota(SubMask.
begin(), SubMask.
end(), 0);
7339 transform(CurrentOrder, It, [K](
unsigned Pos) {
return Pos + K; });
7340 std::advance(It, Sz);
7343 return Data.index() ==
Data.value();
7345 return std::nullopt;
7346 return std::move(ResOrder);
7348 if (TE.State == TreeEntry::StridedVectorize && !TopToBottom &&
7349 (!TE.UserTreeIndex || !TE.UserTreeIndex.UserTE->hasState() ||
7351 (TE.ReorderIndices.empty() ||
isReverseOrder(TE.ReorderIndices)))
7352 return std::nullopt;
7353 if (TE.State == TreeEntry::SplitVectorize ||
7354 ((TE.State == TreeEntry::Vectorize ||
7355 TE.State == TreeEntry::StridedVectorize ||
7356 TE.State == TreeEntry::ExpandVectorize ||
7357 TE.State == TreeEntry::CompressVectorize ||
7358 TE.State == TreeEntry::BlendedLoadVectorize) &&
7361 TE.getMainOp()))))) {
7362 assert((TE.State == TreeEntry::SplitVectorize || !TE.isAltShuffle()) &&
7363 "Alternate instructions are only supported by "
7364 "BinaryOperator and CastInst.");
7365 return TE.ReorderIndices;
7367 if (!TopToBottom && IgnoreReorder && TE.State == TreeEntry::Vectorize &&
7368 TE.isAltShuffle()) {
7369 assert(TE.ReuseShuffleIndices.empty() &&
7370 "ReuseShuffleIndices should be "
7371 "empty for alternate instructions.");
7373 TE.buildAltOpShuffleMask(
7375 assert(TE.getMatchingMainOpOrAltOp(
I) &&
7376 "Unexpected main/alternate opcode");
7380 const int VF = TE.getVectorFactor();
7385 ResOrder[Mask[
I] % VF] =
I;
7387 return std::move(ResOrder);
7389 if (!TE.ReorderIndices.empty())
7390 return TE.ReorderIndices;
7391 if (TE.State == TreeEntry::Vectorize && TE.getOpcode() == Instruction::PHI) {
7392 if (!TE.ReorderIndices.empty())
7393 return TE.ReorderIndices;
7396 for (
auto [
I, V] :
zip(UserBVHead, TE.Scalars)) {
7404 while (
II &&
II->hasOneUse() &&
II->getParent() == BB) {
7412 assert(BB1 != BB2 &&
"Expected different basic blocks.");
7413 if (!DT->isReachableFromEntry(BB1))
7415 if (!DT->isReachableFromEntry(BB2))
7417 auto *NodeA = DT->getNode(BB1);
7418 auto *NodeB = DT->getNode(BB2);
7419 assert(NodeA &&
"Should only process reachable instructions");
7420 assert(NodeB &&
"Should only process reachable instructions");
7421 assert((NodeA == NodeB) ==
7422 (NodeA->getDFSNumIn() == NodeB->getDFSNumIn()) &&
7423 "Different nodes should have different DFS numbers");
7424 return NodeA->getDFSNumIn() < NodeB->getDFSNumIn();
7426 auto PHICompare = [&](
unsigned I1,
unsigned I2) {
7428 Value *V2 = TE.Scalars[I2];
7441 if (FirstUserOfPhi1->getParent() != FirstUserOfPhi2->getParent())
7442 return CompareByBasicBlocks(FirstUserOfPhi1->getParent(),
7443 FirstUserOfPhi2->getParent());
7453 if (UserBVHead[I1] && !UserBVHead[I2])
7455 if (!UserBVHead[I1])
7457 if (UserBVHead[I1] == UserBVHead[I2])
7460 return CompareByBasicBlocks(UserBVHead[I1]->
getParent(),
7462 return UserBVHead[I1]->comesBefore(UserBVHead[I2]);
7475 if (EE1->getOperand(0) == EE2->getOperand(0))
7477 if (!Inst1 && Inst2)
7479 if (Inst1 && Inst2) {
7487 "Expected either instructions or arguments vector operands.");
7488 return P1->getArgNo() < P2->getArgNo();
7493 std::iota(Phis.
begin(), Phis.
end(), 0);
7496 return std::nullopt;
7497 return std::move(Phis);
7499 if (TE.isGather() &&
7500 (!TE.hasState() || !TE.isAltShuffle() ||
7501 ScalarsInSplitNodes.contains(TE.getMainOp())) &&
7507 if (((TE.hasState() && TE.getOpcode() == Instruction::ExtractElement &&
7508 !TE.hasCopyableElements()) ||
7512 auto *EE = dyn_cast<ExtractElementInst>(V);
7513 return !EE || isa<FixedVectorType>(EE->getVectorOperandType());
7519 canReuseExtract(TE.Scalars, CurrentOrder,
true);
7520 if (Reuse || !CurrentOrder.
empty())
7521 return std::move(CurrentOrder);
7529 int Sz = TE.Scalars.size();
7533 if (It == TE.Scalars.begin())
7537 if (It != TE.Scalars.end()) {
7539 unsigned Idx = std::distance(TE.Scalars.begin(), It);
7549 TTI->getVectorInstrCost(Instruction::InsertElement, Ty, CostKind, 0,
7552 TTI->getVectorInstrCost(Instruction::InsertElement, Ty, CostKind,
7554 if (InsertFirstCost + PermuteCost < InsertIdxCost) {
7557 return std::move(Order);
7562 return std::nullopt;
7563 if (TE.Scalars.size() >= 3)
7568 if (TE.hasState() && TE.getOpcode() == Instruction::Load) {
7573 CurrentOrder, PointerOps, SPtrInfo);
7577 return std::move(CurrentOrder);
7579 if (std::optional<OrdersType> CurrentOrder =
7581 return CurrentOrder;
7583 return std::nullopt;
7593 for (
unsigned I = Sz,
E = Mask.size();
I <
E;
I += Sz) {
7601void BoUpSLP::reorderNodeWithReuses(TreeEntry &TE,
ArrayRef<int> Mask)
const {
7604 const unsigned Sz =
TE.Scalars.size();
7606 if (!
TE.isGather() ||
7613 addMask(NewMask,
TE.ReuseShuffleIndices);
7615 TE.ReorderIndices.clear();
7622 for (
auto *It =
TE.ReuseShuffleIndices.begin(),
7623 *End =
TE.ReuseShuffleIndices.end();
7624 It != End; std::advance(It, Sz))
7625 std::iota(It, std::next(It, Sz), 0);
7631 "Expected same size of orders");
7632 size_t Sz = Order.
size();
7635 if (Order[Idx] != Sz)
7636 UsedIndices.
set(Order[Idx]);
7638 if (SecondaryOrder.
empty()) {
7640 if (Order[Idx] == Sz && !UsedIndices.
test(Idx))
7644 if (SecondaryOrder[Idx] != Sz && Order[Idx] == Sz &&
7645 !UsedIndices.
test(SecondaryOrder[Idx]))
7646 Order[Idx] = SecondaryOrder[Idx];
7654 constexpr unsigned TinyVF = 2;
7655 constexpr unsigned TinyTree = 10;
7656 constexpr unsigned PhiOpsLimit = 12;
7657 constexpr unsigned GatherLoadsLimit = 2;
7658 if (VectorizableTree.size() <= TinyTree)
7661 (
getRootNode().getOpcode() == Instruction::Store ||
7664 (
getRootNode().getOpcode() == Instruction::PtrToInt ||
7665 getRootNode().getOpcode() == Instruction::PtrToAddr ||
7666 getRootNode().getOpcode() == Instruction::ICmp))) &&
7678 getRootNode().getOpcode() == Instruction::Store &&
7680 const unsigned ReorderedSplitsCnt =
7681 count_if(VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &TE) {
7682 return TE->State == TreeEntry::SplitVectorize &&
7683 !TE->ReorderIndices.empty() && TE->UserTreeIndex.UserTE &&
7684 TE->UserTreeIndex.UserTE->State == TreeEntry::Vectorize &&
7687 if (ReorderedSplitsCnt <= 1 &&
7689 VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &TE) {
7690 return ((!TE->isGather() &&
7691 (TE->ReorderIndices.empty() ||
7692 (TE->UserTreeIndex.UserTE &&
7693 TE->UserTreeIndex.UserTE->State ==
7694 TreeEntry::Vectorize &&
7695 !TE->UserTreeIndex.UserTE->ReuseShuffleIndices
7697 (TE->isGather() && TE->ReorderIndices.empty() &&
7698 (!TE->hasState() || TE->isAltShuffle() ||
7699 TE->getOpcode() == Instruction::Load ||
7700 TE->getOpcode() == Instruction::ZExt ||
7701 TE->getOpcode() == Instruction::SExt))) &&
7703 !TE->isGather() ||
none_of(TE->Scalars, [&](
Value *V) {
7704 return !isConstant(V) && isVectorized(V);
7706 })) >= VectorizableTree.size() - ReorderedSplitsCnt)
7709 bool HasPhis =
false;
7710 bool HasLoad =
true;
7711 unsigned GatherLoads = 0;
7712 for (
const std::unique_ptr<TreeEntry> &TE :
7713 ArrayRef(VectorizableTree).drop_front()) {
7714 if (TE->State == TreeEntry::SplitVectorize)
7716 if (!TE->hasState()) {
7725 if (TE->getOpcode() == Instruction::Load && TE->ReorderIndices.empty()) {
7726 if (!TE->isGather()) {
7733 if (GatherLoads >= GatherLoadsLimit)
7736 if (TE->getOpcode() == Instruction::GetElementPtr ||
7739 if (TE->getOpcode() != Instruction::PHI &&
7740 (!TE->hasCopyableElements() ||
7742 TE->Scalars.size() / 2))
7745 TE->getNumOperands() > PhiOpsLimit)
7754void BoUpSLP::TreeEntry::reorderSplitNode(
unsigned Idx,
ArrayRef<int> Mask,
7756 assert(State == TreeEntry::SplitVectorize &&
"Expected split user node.");
7759 std::iota(NewMask.
begin(), NewMask.
end(), 0);
7760 std::iota(NewMaskOrder.begin(), NewMaskOrder.end(), 0);
7763 copy(MaskOrder, NewMaskOrder.begin());
7765 assert(Idx == 1 &&
"Expected either 0 or 1 index.");
7766 unsigned Offset = CombinedEntriesWithIndices.
back().second;
7775 ReorderIndices.clear();
7781 if (
auto It = BlocksSchedules.find(TE.getMainOp()->getParent());
7782 It != BlocksSchedules.end())
7783 It->second->markCopyableDepsForRecalc(TE);
7802 ExternalUserReorderMap;
7804 if (
any_of(VectorizableTree, [](
const std::unique_ptr<TreeEntry> &TE) {
7805 return TE->State == TreeEntry::Vectorize &&
7811 const bool IgnoreReorder =
7813 (
getRootNode().getOpcode() == Instruction::InsertElement ||
7814 getRootNode().getOpcode() == Instruction::InsertValue ||
7819 for_each(VectorizableTree, [&, &TTIRef = *TTI](
7820 const std::unique_ptr<TreeEntry> &TE) {
7823 findExternalStoreUsersReorderIndices(TE.get());
7824 if (!ExternalUserReorderIndices.
empty()) {
7825 VFToOrderedEntries[TE->getVectorFactor()].
insert(TE.get());
7827 std::move(ExternalUserReorderIndices));
7833 if (TE->hasState() && TE->isAltShuffle() &&
7834 TE->State != TreeEntry::SplitVectorize) {
7835 Type *ScalarTy = TE->Scalars[0]->getType();
7838 unsigned Opcode0 = TE->getOpcode();
7839 unsigned Opcode1 = TE->getAltOpcode();
7843 if (TTIRef.isLegalAltInstr(VecTy, Opcode0, Opcode1, OpcodeMask)) {
7844 VFToOrderedEntries[TE->getVectorFactor()].
insert(TE.get());
7850 if (std::optional<OrdersType> CurrentOrder =
7860 const TreeEntry *UserTE = TE.get();
7862 if (!UserTE->UserTreeIndex)
7864 if (UserTE->UserTreeIndex.UserTE->State == TreeEntry::Vectorize &&
7865 UserTE->UserTreeIndex.UserTE->isAltShuffle() &&
7866 UserTE->UserTreeIndex.UserTE->Idx != 0)
7868 UserTE = UserTE->UserTreeIndex.UserTE;
7871 VFToOrderedEntries[TE->getVectorFactor()].
insert(TE.get());
7872 if (!(TE->State == TreeEntry::Vectorize ||
7873 TE->State == TreeEntry::StridedVectorize ||
7874 TE->State == TreeEntry::ExpandVectorize ||
7875 TE->State == TreeEntry::SplitVectorize ||
7876 TE->State == TreeEntry::CompressVectorize ||
7877 TE->State == TreeEntry::BlendedLoadVectorize) ||
7878 !TE->ReuseShuffleIndices.empty())
7879 GathersToOrders.
try_emplace(TE.get(), *CurrentOrder);
7880 if (TE->State == TreeEntry::Vectorize &&
7881 TE->getOpcode() == Instruction::PHI)
7882 PhisToOrders.
try_emplace(TE.get(), *CurrentOrder);
7887 for (
unsigned VF =
getRootNode().getVectorFactor();
7888 !VFToOrderedEntries.
empty() && VF > 1; --VF) {
7889 auto It = VFToOrderedEntries.
find(VF);
7890 if (It == VFToOrderedEntries.
end())
7904 for (
const TreeEntry *OpTE : OrderedEntries) {
7907 if (!OpTE->ReuseShuffleIndices.empty() && !GathersToOrders.
count(OpTE) &&
7908 OpTE->State != TreeEntry::SplitVectorize)
7911 const auto &Order = [OpTE, &GathersToOrders, &AltShufflesToOrders,
7913 if (OpTE->isGather() || !OpTE->ReuseShuffleIndices.empty()) {
7914 auto It = GathersToOrders.find(OpTE);
7915 if (It != GathersToOrders.end())
7918 if (OpTE->hasState() && OpTE->isAltShuffle()) {
7919 auto It = AltShufflesToOrders.find(OpTE);
7920 if (It != AltShufflesToOrders.end())
7923 if (OpTE->State == TreeEntry::Vectorize &&
7924 OpTE->getOpcode() == Instruction::PHI) {
7925 auto It = PhisToOrders.
find(OpTE);
7926 if (It != PhisToOrders.
end())
7929 return OpTE->ReorderIndices;
7932 auto It = ExternalUserReorderMap.
find(OpTE);
7933 if (It != ExternalUserReorderMap.
end()) {
7934 const auto &ExternalUserReorderIndices = It->second;
7938 if (OpTE->getVectorFactor() != OpTE->Scalars.size()) {
7939 OrdersUses.try_emplace(
OrdersType(), 0).first->second +=
7940 ExternalUserReorderIndices.size();
7942 for (
const OrdersType &ExtOrder : ExternalUserReorderIndices)
7943 ++OrdersUses.try_emplace(ExtOrder, 0).first->second;
7950 if (OpTE->State == TreeEntry::Vectorize &&
7951 OpTE->getOpcode() == Instruction::Store && !Order.
empty()) {
7952 assert(!OpTE->isAltShuffle() &&
7953 "Alternate instructions are only supported by BinaryOperator "
7957 unsigned E = Order.
size();
7960 return Idx == PoisonMaskElem ? E : static_cast<unsigned>(Idx);
7963 ++OrdersUses.try_emplace(CurrentOrder, 0).first->second;
7965 ++OrdersUses.try_emplace(Order, 0).first->second;
7968 if (OrdersUses.empty())
7971 unsigned IdentityCnt = 0;
7972 unsigned FilledIdentityCnt = 0;
7974 for (
auto &Pair : OrdersUses) {
7976 if (!Pair.first.empty())
7977 FilledIdentityCnt += Pair.second;
7978 IdentityCnt += Pair.second;
7983 unsigned Cnt = IdentityCnt;
7984 for (
auto &Pair : OrdersUses) {
7988 if (Cnt < Pair.second ||
7989 (Cnt == IdentityCnt && IdentityCnt == FilledIdentityCnt &&
7990 Cnt == Pair.second && !BestOrder.
empty() &&
7993 BestOrder = Pair.first;
8006 unsigned E = BestOrder.
size();
8008 return I < E ? static_cast<int>(I) : PoisonMaskElem;
8011 for (std::unique_ptr<TreeEntry> &TE : VectorizableTree) {
8013 if (TE->Scalars.size() != VF) {
8014 if (TE->ReuseShuffleIndices.size() == VF &&
8015 TE->State != TreeEntry::ExpandVectorize) {
8016 assert(TE->State != TreeEntry::SplitVectorize &&
8017 "Split vectorized not expected.");
8022 (!TE->UserTreeIndex ||
8023 TE->UserTreeIndex.UserTE->Scalars.size() == VF ||
8024 TE->UserTreeIndex.UserTE->Scalars.size() == TE->Scalars.size() ||
8025 TE->UserTreeIndex.UserTE->State == TreeEntry::SplitVectorize) &&
8026 "All users must be of VF size.");
8033 if (TE->UserTreeIndex && TE->UserTreeIndex.UserTE->hasState() &&
8039 reorderNodeWithReuses(*TE, Mask);
8041 if (TE->UserTreeIndex &&
8042 TE->UserTreeIndex.UserTE->State == TreeEntry::SplitVectorize)
8043 TE->UserTreeIndex.UserTE->reorderSplitNode(
8044 TE->UserTreeIndex.EdgeIdx, Mask, MaskOrder);
8048 if ((TE->State == TreeEntry::SplitVectorize &&
8049 TE->ReuseShuffleIndices.empty()) ||
8050 ((TE->State == TreeEntry::Vectorize ||
8051 TE->State == TreeEntry::StridedVectorize ||
8052 TE->State == TreeEntry::ExpandVectorize ||
8053 TE->State == TreeEntry::CompressVectorize ||
8054 TE->State == TreeEntry::BlendedLoadVectorize) &&
8059 (!TE->isAltShuffle() || (TE->State == TreeEntry::SplitVectorize &&
8060 TE->ReuseShuffleIndices.empty())) &&
8061 "Alternate instructions are only supported by BinaryOperator "
8068 TE->reorderOperands(Mask);
8073 TE->reorderOperands(Mask);
8075 assert(TE->ReorderIndices.empty() &&
8076 "Expected empty reorder sequence.");
8079 if (!TE->ReuseShuffleIndices.empty() &&
8080 TE->State != TreeEntry::ExpandVectorize) {
8089 addMask(NewReuses, TE->ReuseShuffleIndices);
8090 TE->ReuseShuffleIndices.swap(NewReuses);
8091 }
else if (TE->UserTreeIndex &&
8092 TE->UserTreeIndex.UserTE->State == TreeEntry::SplitVectorize)
8094 TE->UserTreeIndex.UserTE->reorderSplitNode(TE->UserTreeIndex.EdgeIdx,
8100void BoUpSLP::buildReorderableOperands(
8101 TreeEntry *UserTE,
SmallVectorImpl<std::pair<unsigned, TreeEntry *>> &Edges,
8105 if (
any_of(Edges, [
I](
const std::pair<unsigned, TreeEntry *> &OpData) {
8106 return OpData.first ==
I &&
8107 (OpData.second->State == TreeEntry::Vectorize ||
8108 OpData.second->State == TreeEntry::StridedVectorize ||
8109 OpData.second->State == TreeEntry::ExpandVectorize ||
8110 OpData.second->State == TreeEntry::CompressVectorize ||
8111 OpData.second->State == TreeEntry::BlendedLoadVectorize ||
8112 OpData.second->State == TreeEntry::SplitVectorize);
8116 if (UserTE->hasState()) {
8117 if (UserTE->getOpcode() == Instruction::ExtractElement ||
8118 UserTE->getOpcode() == Instruction::ExtractValue)
8120 if ((UserTE->getOpcode() == Instruction::InsertElement ||
8121 UserTE->getOpcode() == Instruction::InsertValue) &&
8124 if (UserTE->getOpcode() == Instruction::Store &&
I == 1 &&
8125 (UserTE->State == TreeEntry::Vectorize ||
8126 UserTE->State == TreeEntry::StridedVectorize ||
8127 UserTE->State == TreeEntry::ExpandVectorize))
8129 if (UserTE->getOpcode() == Instruction::Load &&
8130 (UserTE->State == TreeEntry::Vectorize ||
8131 UserTE->State == TreeEntry::StridedVectorize ||
8132 UserTE->State == TreeEntry::CompressVectorize ||
8133 UserTE->State == TreeEntry::BlendedLoadVectorize))
8136 TreeEntry *
TE = getOperandEntry(UserTE,
I);
8137 assert(TE &&
"Expected operand entry.");
8138 if (!
TE->isGather()) {
8141 Edges.emplace_back(
I, TE);
8147 if (
TE->State == TreeEntry::ScatterVectorize &&
8148 TE->ReuseShuffleIndices.empty() &&
TE->ReorderIndices.empty())
8152 if (ReorderableGathers.
contains(TE))
8158 struct TreeEntryCompare {
8159 bool operator()(
const TreeEntry *LHS,
const TreeEntry *RHS)
const {
8160 if (LHS->UserTreeIndex && RHS->UserTreeIndex)
8161 return LHS->UserTreeIndex.UserTE->Idx < RHS->UserTreeIndex.UserTE->Idx;
8162 return LHS->Idx < RHS->Idx;
8171 for (
const std::unique_ptr<TreeEntry> &TE : VectorizableTree) {
8172 if (TE->State != TreeEntry::Vectorize &&
8173 TE->State != TreeEntry::StridedVectorize &&
8174 TE->State != TreeEntry::ExpandVectorize &&
8175 TE->State != TreeEntry::CompressVectorize &&
8176 TE->State != TreeEntry::BlendedLoadVectorize &&
8177 TE->State != TreeEntry::SplitVectorize)
8178 NonVectorized.
insert(TE.get());
8179 if (std::optional<OrdersType> CurrentOrder =
8181 Queue.push(TE.get());
8182 if (!(TE->State == TreeEntry::Vectorize ||
8183 TE->State == TreeEntry::StridedVectorize ||
8184 TE->State == TreeEntry::ExpandVectorize ||
8185 TE->State == TreeEntry::CompressVectorize ||
8186 TE->State == TreeEntry::BlendedLoadVectorize ||
8187 TE->State == TreeEntry::SplitVectorize) ||
8188 !TE->ReuseShuffleIndices.empty())
8189 GathersToOrders.
insert(TE.get());
8198 while (!Queue.empty()) {
8200 std::pair<TreeEntry *, SmallVector<std::pair<unsigned, TreeEntry *>>>
Users;
8201 TreeEntry *TE = Queue.top();
8202 const TreeEntry *UserTE = TE->UserTreeIndex.UserTE;
8205 while (!Queue.empty()) {
8207 if (!UserTE || UserTE != TE->UserTreeIndex.UserTE)
8212 for (TreeEntry *TE : OrderedOps) {
8213 if (!(TE->State == TreeEntry::Vectorize ||
8214 TE->State == TreeEntry::StridedVectorize ||
8215 TE->State == TreeEntry::ExpandVectorize ||
8216 TE->State == TreeEntry::CompressVectorize ||
8217 TE->State == TreeEntry::BlendedLoadVectorize ||
8218 TE->State == TreeEntry::SplitVectorize ||
8219 (TE->isGather() && GathersToOrders.
contains(TE))) ||
8220 !TE->UserTreeIndex ||
8221 TE->UserTreeIndex.UserTE->State == TreeEntry::BlendedLoadVectorize ||
8222 !TE->ReuseShuffleIndices.empty() || !Visited.
insert(TE).second)
8226 Users.first = TE->UserTreeIndex.UserTE;
8227 Users.second.emplace_back(TE->UserTreeIndex.EdgeIdx, TE);
8232 if (
Data.first->State == TreeEntry::Vectorize &&
8235 if (
Data.first->State == TreeEntry::SplitVectorize) {
8237 Data.second.size() <= 2 &&
8238 "Expected not greater than 2 operands for split vectorize node.");
8240 [](
const auto &
Op) { return !Op.second->UserTreeIndex; }))
8243 assert(
Data.first->CombinedEntriesWithIndices.size() == 2 &&
8244 "Expected exactly 2 entries.");
8245 for (
const auto &
P :
Data.first->CombinedEntriesWithIndices) {
8246 TreeEntry &OpTE = *VectorizableTree[
P.first];
8252 if (OpTE.State != TreeEntry::SplitVectorize &&
8253 !OpTE.ReorderIndices.empty() && !OpTE.ReuseShuffleIndices.empty())
8256 if (Order.
empty() || !OpTE.ReuseShuffleIndices.empty()) {
8257 if (!OpTE.isGather() && OpTE.ReuseShuffleIndices.empty())
8259 const auto BestOrder =
8268 const unsigned E = Order.
size();
8271 return I < E ? static_cast<int>(I) : PoisonMaskElem;
8273 Data.first->reorderSplitNode(
P.second ? 1 : 0, Mask, MaskOrder);
8275 if (!OpTE.ReorderIndices.empty()) {
8276 OpTE.ReorderIndices.clear();
8277 }
else if (!OpTE.ReuseShuffleIndices.empty()) {
8280 assert(OpTE.isGather() &&
"Expected only gather/buildvector node.");
8284 if (
Data.first->ReuseShuffleIndices.empty() &&
8285 !
Data.first->ReorderIndices.empty()) {
8288 Queue.push(
Data.first);
8296 !
Data.first->UserTreeIndex &&
8297 Data.first->State == TreeEntry::Vectorize &&
8298 Data.first->getOpcode() == Instruction::PHI &&
8299 Data.first->ReuseShuffleIndices.empty())
8303 buildReorderableOperands(
Data.first,
Data.second, NonVectorized,
8315 for (
const auto &
Op :
Data.second) {
8316 TreeEntry *OpTE =
Op.second;
8317 if (!VisitedOps.
insert(OpTE).second)
8319 if (!OpTE->ReuseShuffleIndices.empty() && !GathersToOrders.
count(OpTE))
8321 const auto Order = [&]() ->
const OrdersType {
8322 if (OpTE->isGather() || !OpTE->ReuseShuffleIndices.empty())
8326 return OpTE->ReorderIndices;
8330 if (Order.
size() == 1)
8336 Value *Root = OpTE->hasState()
8339 auto GetSameNodesUsers = [&](
Value *Root) {
8341 for (
const TreeEntry *TE : ValueToGatherNodes.lookup(Root)) {
8342 if (TE != OpTE && TE->UserTreeIndex &&
8343 TE->getVectorFactor() == OpTE->getVectorFactor() &&
8344 TE->Scalars.size() == OpTE->Scalars.size() &&
8345 ((TE->ReorderIndices.empty() && OpTE->isSame(TE->Scalars)) ||
8346 (OpTE->ReorderIndices.empty() && TE->isSame(OpTE->Scalars))))
8347 Res.
insert(TE->UserTreeIndex.UserTE);
8349 for (
const TreeEntry *TE : getTreeEntries(Root)) {
8350 if (TE != OpTE && TE->UserTreeIndex &&
8351 TE->getVectorFactor() == OpTE->getVectorFactor() &&
8352 TE->Scalars.size() == OpTE->Scalars.size() &&
8353 ((TE->ReorderIndices.empty() && OpTE->isSame(TE->Scalars)) ||
8354 (OpTE->ReorderIndices.empty() && TE->isSame(OpTE->Scalars))))
8355 Res.
insert(TE->UserTreeIndex.UserTE);
8359 auto GetNumOperands = [](
const TreeEntry *TE) {
8360 if (TE->State == TreeEntry::SplitVectorize)
8361 return TE->getNumOperands();
8363 return CI->arg_size();
8364 return TE->getNumOperands();
8366 auto NodeShouldBeReorderedWithOperands = [&, TTI = TTI](
8367 const TreeEntry *TE) {
8375 const TreeEntry *
Op = getOperandEntry(TE, Idx);
8376 if (
Op->isGather() &&
Op->hasState()) {
8377 const TreeEntry *VecOp =
8378 getSameValuesTreeEntry(
Op->getMainOp(),
Op->Scalars);
8382 if (
Op->ReorderIndices.empty() &&
Op->ReuseShuffleIndices.empty())
8389 if (!RevisitedOps.
insert(UTE).second)
8391 return UTE ==
Data.first || !UTE->ReorderIndices.empty() ||
8392 !UTE->ReuseShuffleIndices.empty() ||
8393 (UTE->UserTreeIndex &&
8394 UTE->UserTreeIndex.UserTE ==
Data.first) ||
8395 (
Data.first->UserTreeIndex &&
8396 Data.first->UserTreeIndex.UserTE == UTE) ||
8397 (IgnoreReorder && UTE->UserTreeIndex &&
8398 UTE->UserTreeIndex.UserTE->Idx == 0) ||
8399 NodeShouldBeReorderedWithOperands(UTE);
8402 for (TreeEntry *UTE :
Users) {
8410 const TreeEntry *
Op = getOperandEntry(UTE, Idx);
8412 Queue.push(
const_cast<TreeEntry *
>(
Op));
8417 Data.second, [OpTE](
const std::pair<unsigned, TreeEntry *> &
P) {
8418 return P.second == OpTE;
8421 if (OpTE->State == TreeEntry::Vectorize &&
8422 OpTE->getOpcode() == Instruction::Store && !Order.
empty()) {
8423 assert(!OpTE->isAltShuffle() &&
8424 "Alternate instructions are only supported by BinaryOperator "
8428 unsigned E = Order.
size();
8431 return Idx == PoisonMaskElem ? E : static_cast<unsigned>(Idx);
8434 OrdersUses.try_emplace(CurrentOrder, 0).first->second +=
NumOps;
8436 OrdersUses.try_emplace(Order, 0).first->second +=
NumOps;
8438 auto Res = OrdersUses.try_emplace(
OrdersType(), 0);
8439 const auto AllowsReordering = [&](
const TreeEntry *TE) {
8440 if (!TE->ReorderIndices.empty() || !TE->ReuseShuffleIndices.empty() ||
8441 (TE->State == TreeEntry::Vectorize && TE->isAltShuffle()) ||
8442 (IgnoreReorder && TE->Idx == 0))
8444 if (TE->isGather()) {
8454 if (OpTE->UserTreeIndex) {
8455 TreeEntry *UserTE = OpTE->UserTreeIndex.UserTE;
8456 if (!VisitedUsers.
insert(UserTE).second)
8461 if (AllowsReordering(UserTE))
8469 if (
static_cast<unsigned>(
count_if(
8470 Ops, [UserTE, &AllowsReordering](
8471 const std::pair<unsigned, TreeEntry *> &
Op) {
8472 return AllowsReordering(
Op.second) &&
8473 Op.second->UserTreeIndex.UserTE == UserTE;
8474 })) <=
Ops.size() / 2)
8475 ++Res.first->second;
8478 if (OrdersUses.empty()) {
8483 unsigned IdentityCnt = 0;
8484 unsigned VF =
Data.second.front().second->getVectorFactor();
8486 for (
auto &Pair : OrdersUses) {
8488 IdentityCnt += Pair.second;
8493 unsigned Cnt = IdentityCnt;
8494 for (
auto &Pair : OrdersUses) {
8498 if (Cnt < Pair.second) {
8500 BestOrder = Pair.first;
8517 unsigned E = BestOrder.
size();
8519 return I < E ? static_cast<int>(I) : PoisonMaskElem;
8521 for (
const std::pair<unsigned, TreeEntry *> &
Op :
Data.second) {
8522 TreeEntry *TE =
Op.second;
8523 if (!VisitedOps.
insert(TE).second)
8526 if (TE->State == TreeEntry::Vectorize &&
8529 if (TE->ReuseShuffleIndices.size() == BestOrder.
size()) {
8530 reorderNodeWithReuses(*TE, Mask);
8534 if (TE->State != TreeEntry::Vectorize &&
8535 TE->State != TreeEntry::StridedVectorize &&
8536 TE->State != TreeEntry::ExpandVectorize &&
8537 TE->State != TreeEntry::CompressVectorize &&
8538 TE->State != TreeEntry::BlendedLoadVectorize &&
8539 TE->State != TreeEntry::SplitVectorize &&
8540 (TE->State != TreeEntry::ScatterVectorize ||
8541 TE->ReorderIndices.empty()))
8543 assert((BestOrder.
size() == TE->ReorderIndices.size() ||
8544 TE->ReorderIndices.empty()) &&
8545 "Non-matching sizes of user/operand entries.");
8548 IgnoreReorder =
false;
8551 for (TreeEntry *
Gather : GatherOps) {
8553 "Unexpected reordering of gathers.");
8554 if (!
Gather->ReuseShuffleIndices.empty()) {
8565 if (
Gather->State == TreeEntry::ScatterVectorize) {
8575 auto IsNotProfitableAltCodeNode = [](
const TreeEntry &TE) {
8576 return TE.isAltShuffle() &&
8577 (!TE.ReuseShuffleIndices.empty() || TE.getVectorFactor() == 2 ||
8578 TE.ReorderIndices.empty());
8580 if (
Data.first->State != TreeEntry::Vectorize ||
8582 Data.first->getMainOp()) ||
8583 IsNotProfitableAltCodeNode(*
Data.first)) {
8584 Data.first->reorderOperands(Mask);
8588 Data.first->getMainOp()) ||
8589 IsNotProfitableAltCodeNode(*
Data.first) ||
8590 Data.first->State == TreeEntry::CompressVectorize) {
8594 if (
Data.first->ReuseShuffleIndices.empty() &&
8595 !
Data.first->ReorderIndices.empty() &&
8596 !IsNotProfitableAltCodeNode(*
Data.first)) {
8599 Queue.push(
Data.first);
8612Instruction *BoUpSLP::getRootEntryInstruction(
const TreeEntry &Entry)
const {
8613 if (Entry.hasState() &&
8614 (Entry.getOpcode() == Instruction::Store ||
8615 Entry.getOpcode() == Instruction::Load) &&
8616 Entry.State == TreeEntry::StridedVectorize &&
8617 !Entry.ReorderIndices.empty() &&
isReverseOrder(Entry.ReorderIndices))
8624 const size_t NumVectScalars = ScalarToTreeEntries.size() + 1;
8630 KeptReassocScalars.
clear();
8632 for (
const auto &[V, Owners] : ReassocScalarToTreeEntries)
8633 if ((
isGathered(V) || !getTreeEntries(V).empty() ||
8635 [V = V](
const TreeEntry *TE) {
8636 return TE->isCopyableElement(
const_cast<Value *
>(V));
8638 KeptReassocScalars.insert(V).second)
8640 while (!KeptWorklist.
empty()) {
8643 if (ReassocScalarToTreeEntries.contains(
Op) &&
8644 KeptReassocScalars.insert(
Op).second)
8648 for (
auto &TEPtr : VectorizableTree) {
8649 TreeEntry *Entry = TEPtr.get();
8652 if (Entry->isGather() || Entry->State == TreeEntry::SplitVectorize ||
8653 DeletedNodes.contains(Entry) ||
8654 TransformedToGatherNodes.contains(Entry))
8658 for (
int Lane = 0, LE = Entry->Scalars.size(); Lane != LE; ++Lane) {
8659 Value *Scalar = Entry->Scalars[Lane];
8665 auto It = ScalarToExtUses.
find(Scalar);
8666 if (It != ScalarToExtUses.
end() && !ExternalUses[It->second].User)
8669 if (!IsStructScalar && Scalar->hasNUsesOrMore(NumVectScalars)) {
8670 unsigned FoundLane = Entry->findLaneForValue(Scalar);
8671 LLVM_DEBUG(
dbgs() <<
"SLP: Need to extract from lane " << FoundLane
8672 <<
" from " << *Scalar <<
"for many users.\n");
8673 It = ScalarToExtUses.
try_emplace(Scalar, ExternalUses.size()).first;
8674 ExternalUses.emplace_back(Scalar,
nullptr, *Entry, FoundLane);
8675 ExternalUsesWithNonUsers.insert(Scalar);
8680 const auto ExtI = ExternallyUsedValues.
find(Scalar);
8681 if (ExtI != ExternallyUsedValues.
end()) {
8682 unsigned FoundLane = Entry->findLaneForValue(Scalar);
8683 LLVM_DEBUG(
dbgs() <<
"SLP: Need to extract: Extra arg from lane "
8684 << FoundLane <<
" from " << *Scalar <<
".\n");
8685 ScalarToExtUses.
try_emplace(Scalar, ExternalUses.size());
8686 ExternalUses.emplace_back(Scalar,
nullptr, *Entry, FoundLane);
8697 if (UserIgnoreList && UserIgnoreList->contains(UserInst))
8704 !KeptReassocScalars.contains(UserInst)) {
8705 LLVM_DEBUG(
dbgs() <<
"SLP: \tInternal (reassociated) user will be "
8713 any_of(UseEntries, [
this](
const TreeEntry *UseEntry) {
8714 return !DeletedNodes.contains(UseEntry) &&
8715 !TransformedToGatherNodes.contains(UseEntry);
8720 if (!((Scalar->getType()->getScalarType()->isPointerTy() &&
8723 all_of(UseEntries, [&](TreeEntry *UseEntry) {
8724 if (DeletedNodes.contains(UseEntry) ||
8725 TransformedToGatherNodes.contains(UseEntry))
8727 return UseEntry->State == TreeEntry::ScatterVectorize ||
8729 Scalar, getRootEntryInstruction(*UseEntry), TLI,
8732 LLVM_DEBUG(
dbgs() <<
"SLP: \tInternal user will be removed:" << *U
8735 [](TreeEntry *UseEntry) {
8736 return UseEntry->isGather();
8741 if (!IsStructScalar) {
8743 if (It != ScalarToExtUses.
end()) {
8744 ExternalUses[It->second].User =
nullptr;
8750 if (U && !IsStructScalar && Scalar->hasNUsesOrMore(
UsesLimit))
8752 unsigned FoundLane = Entry->findLaneForValue(Scalar);
8754 <<
" from lane " << FoundLane <<
" from " << *Scalar
8756 It = ScalarToExtUses.
try_emplace(Scalar, ExternalUses.size()).first;
8757 ExternalUses.emplace_back(Scalar, U, *Entry, FoundLane);
8758 ExternalUsesWithNonUsers.insert(Scalar);
8769 for (
const auto &[StridedTE, SPtrInfo] : TreeEntryToStridedPtrInfoMap)
8770 if (SPtrInfo.StrideSCEV && !SPtrInfo.StrideVal &&
8771 !DeletedNodes.contains(StridedTE) &&
8772 !TransformedToGatherNodes.contains(StridedTE))
8774 StridedTE->getMainOp()->getParent());
8775 if (Strides.
empty())
8777 for (
const std::unique_ptr<TreeEntry> &TEPtr : VectorizableTree) {
8778 TreeEntry *Entry = TEPtr.get();
8779 if (Entry->isGather() || Entry->State == TreeEntry::SplitVectorize ||
8780 DeletedNodes.contains(Entry) ||
8781 TransformedToGatherNodes.contains(Entry))
8783 for (
Value *Scalar : Entry->Scalars) {
8785 if (!
I || Entry->isCopyableElement(
I) || !SE->isSCEVable(
I->getType()))
8787 const SCEV *ScalarSCEV = SE->getSCEV(
I);
8789 none_of(Strides, [&](
const auto &Stride) {
8790 return DT->dominates(
I, Stride.second->getTerminator()) &&
8792 return S == ScalarSCEV;
8796 auto It = ScalarToExtUses.
find(Scalar);
8797 if (It != ScalarToExtUses.
end()) {
8800 ExternalUses[It->second].User =
nullptr;
8803 unsigned FoundLane = Entry->findLaneForValue(Scalar);
8804 LLVM_DEBUG(
dbgs() <<
"SLP: Need to extract: strided load stride from "
8806 << FoundLane <<
" from " << *Scalar <<
".\n");
8807 ScalarToExtUses.
try_emplace(Scalar, ExternalUses.size());
8808 ExternalUses.emplace_back(Scalar,
nullptr, *Entry, FoundLane);
8809 ExternalUsesWithNonUsers.insert(Scalar);
8815BoUpSLP::collectUserStores(
const BoUpSLP::TreeEntry *TE)
const {
8819 for (
unsigned Lane :
seq<unsigned>(0, TE->Scalars.size())) {
8820 Value *V = TE->Scalars[Lane];
8833 if (
SI ==
nullptr || !
SI->isSimple() ||
SI->getFunction() !=
F ||
8842 auto &StoresVec = PtrToStoresMap[{
SI->getParent(),
8843 SI->getValueOperand()->getType(), Ptr}];
8846 if (StoresVec.size() > Lane)
8848 if (!StoresVec.empty()) {
8850 SI->getValueOperand()->getType(),
SI->getPointerOperand(),
8851 SI->getValueOperand()->getType(),
8852 StoresVec.front()->getPointerOperand(), *
DL, *SE,
8858 StoresVec.push_back(SI);
8863 for (
auto &
P : PtrToStoresMap) {
8878 StoreInst *S0 = StoresVec[0];
8883 StoreInst *
SI = StoresVec[Idx];
8884 std::optional<int64_t> Diff =
8886 SI->getPointerOperand(), *DL, *SE,
8892 if (StoreOffsetVec.
size() != StoresVec.
size())
8894 sort(StoreOffsetVec, llvm::less_first());
8896 int64_t PrevDist = 0;
8897 for (
const auto &
P : StoreOffsetVec) {
8898 if (Idx > 0 &&
P.first != PrevDist + 1)
8906 ReorderIndices.assign(StoresVec.
size(), 0);
8907 bool IsIdentity =
true;
8909 ReorderIndices[
P.second] =
I;
8910 IsIdentity &=
P.second ==
I;
8916 ReorderIndices.clear();
8923 for (
unsigned Idx : Order)
8924 dbgs() << Idx <<
", ";
8930BoUpSLP::findExternalStoreUsersReorderIndices(TreeEntry *TE)
const {
8931 unsigned NumLanes =
TE->Scalars.size();
8944 if (StoresVec.
size() != NumLanes)
8949 if (!canFormVector(StoresVec, ReorderIndices))
8954 ExternalReorderIndices.
push_back(ReorderIndices);
8956 return ExternalReorderIndices;
8962 assert(TreeEntryToStridedPtrInfoMap.empty() &&
8963 "TreeEntryToStridedPtrInfoMap is not cleared");
8964 UserIgnoreList = &UserIgnoreLst;
8967 buildTreeRec(Roots, 0,
EdgeInfo());
8969 tryToVectorizeSplatGatheredScalars();
8974 assert(TreeEntryToStridedPtrInfoMap.empty() &&
8975 "TreeEntryToStridedPtrInfoMap is not cleared");
8978 buildTreeRec(Roots, 0,
EdgeInfo());
8980 tryToVectorizeSplatGatheredScalars();
8989 bool AddNew =
true) {
8997 for (
Value *V : VL) {
9001 if (R.isDeleted(LI) || R.isVectorized(LI) || !LI->isSimple())
9003 bool IsFound =
false;
9004 for (
auto [Map,
Data] :
zip(ClusteredDistToLoad, ClusteredLoads)) {
9005 assert(LI->getParent() ==
Data.front().first->getParent() &&
9006 LI->getType() ==
Data.front().first->getType() &&
9010 "Expected loads with the same type, same parent and same "
9011 "underlying pointer.");
9013 LI->getType(), LI->getPointerOperand(),
Data.front().first->getType(),
9014 Data.front().first->getPointerOperand(),
DL, SE,
9018 auto It = Map.find(*Dist);
9019 if (It != Map.end() && It->second != LI)
9021 if (It == Map.end()) {
9022 Data.emplace_back(LI, *Dist);
9023 Map.try_emplace(*Dist, LI);
9033 auto FindMatchingLoads =
9038 int64_t &
Offset,
unsigned &Start) {
9040 return GatheredLoads.
end();
9049 std::optional<int64_t> Dist =
9051 Data.front().first->getType(),
9052 Data.front().first->getPointerOperand(),
DL, SE,
9058 for (std::pair<LoadInst *, int64_t>
P :
Data) {
9064 unsigned NumUniques = 0;
9065 for (
auto [Cnt, Pair] :
enumerate(Loads)) {
9066 bool Used = DataLoads.
contains(Pair.first);
9067 if (!Used && !DataDists.
contains(*Dist + Pair.second)) {
9074 if (NumUniques > 0 &&
9075 (Loads.
size() == NumUniques ||
9076 (Loads.
size() - NumUniques >= 2 &&
9077 Loads.
size() - NumUniques >= Loads.
size() / 2 &&
9083 return std::next(GatheredLoads.
begin(), Idx);
9087 return GatheredLoads.
end();
9089 for (
ArrayRef<std::pair<LoadInst *, int64_t>>
Data : ClusteredLoads) {
9093 auto *It = FindMatchingLoads(
Data, GatheredLoads, LocalToAdd,
Repeated,
9095 while (It != GatheredLoads.
end()) {
9096 assert(!LocalToAdd.
empty() &&
"Expected some elements to add.");
9097 for (
unsigned Idx : LocalToAdd)
9104 return !ToAdd.contains(Idx) && !Repeated.contains(Idx);
9111 Loads.push_back(
Data[Idx]);
9117 GatheredLoads, [&](
ArrayRef<std::pair<LoadInst *, int64_t>> PD) {
9118 return PD.front().first->getParent() == LI->
getParent() &&
9119 PD.front().first->getType() == LI->
getType();
9121 while (It != GatheredLoads.
end()) {
9124 std::next(It), GatheredLoads.
end(),
9125 [&](
ArrayRef<std::pair<LoadInst *, int64_t>> PD) {
9126 return PD.front().first->getParent() == LI->getParent() &&
9127 PD.front().first->getType() == LI->getType();
9131 GatheredLoads.emplace_back().append(
Data.begin(),
Data.end());
9132 AddNewLoads(GatheredLoads.emplace_back());
9137void BoUpSLP::tryToVectorizeGatheredLoads(
9138 const SmallMapVector<
9139 std::tuple<BasicBlock *, Value *, Type *>,
9142 GatheredLoadsEntriesFirst = VectorizableTree.
size();
9145 LoadEntriesToVectorize.size());
9146 for (
auto [Idx, Set] :
zip(LoadEntriesToVectorize, LoadSetsToVectorize))
9147 Set.insert_range(VectorizableTree[Idx]->Scalars);
9150 auto LoadSorter = [](
const std::pair<LoadInst *, int64_t> &L1,
9151 const std::pair<LoadInst *, int64_t> &L2) {
9152 return L1.second > L2.second;
9161 return TTI->isLegalMaskedGather(Ty, Alignment) &&
9162 !TTI->forceScalarizeMaskedGather(Ty, Alignment);
9167 SmallVectorImpl<LoadInst *> &NonVectorized,
9168 bool Final,
unsigned MaxVF) {
9170 unsigned StartIdx = 0;
9171 SmallVector<int> CandidateVFs;
9184 if (Final && CandidateVFs.
empty())
9187 unsigned BestVF = Final ? CandidateVFs.
back() : 0;
9188 for (
unsigned NumElts : CandidateVFs) {
9189 if (Final && NumElts > BestVF)
9191 SmallVector<unsigned> MaskedGatherVectorized;
9192 for (
unsigned Cnt = StartIdx,
E = Loads.
size(); Cnt <
E;
9196 if (VectorizedLoads.count(Slice.
front()) ||
9197 VectorizedLoads.count(Slice.
back()) ||
9203 bool AllowToVectorize =
false;
9206 bool IsLegalBroadcastLoad = TTI->isLegalBroadcastLoad(
9209 for (LoadInst *LI : Slice) {
9211 if (LI->hasOneUse())
9217 if (
static_cast<unsigned int>(std::distance(
9218 LI->user_begin(), LI->user_end())) != LI->getNumUses())
9220 if (!IsLegalBroadcastLoad)
9224 for (User *U : LI->users()) {
9227 for (
const TreeEntry *UTE : getTreeEntries(U)) {
9228 for (
int I :
seq<int>(UTE->getNumOperands())) {
9230 return V == LI || isa<PoisonValue>(V);
9240 AllowToVectorize = CheckIfAllowed(Slice);
9244 any_of(ValueToGatherNodes.at(Slice.front()),
9245 [=](
const TreeEntry *TE) {
9246 return TE->Scalars.size() == 2 &&
9247 ((TE->Scalars.front() == Slice.front() &&
9248 TE->Scalars.back() == Slice.back()) ||
9249 (TE->Scalars.front() == Slice.back() &&
9250 TE->Scalars.back() == Slice.front()));
9253 if (AllowToVectorize) {
9258 reinterpret_cast<Value *
const *
>(Slice.begin()), Slice.size());
9261 PointerOps, SPtrInfo, &BestVF);
9263 (BestVF > 1 &&
static_cast<unsigned>(NumElts) == 2 * BestVF)) {
9265 if (MaskedGatherVectorized.
empty() ||
9266 Cnt >= MaskedGatherVectorized.
back() + NumElts)
9272 VectorizedLoads.insert_range(Slice);
9275 if (Cnt == StartIdx)
9276 StartIdx += NumElts;
9279 if (StartIdx >= Loads.
size())
9283 if (!MaskedGatherVectorized.
empty() &&
9284 Cnt < MaskedGatherVectorized.
back() + NumElts)
9290 if (!AllowToVectorize || BestVF == 0)
9294 for (
unsigned Cnt : MaskedGatherVectorized) {
9296 Cnt, std::min<unsigned>(NumElts, Loads.
size() - Cnt));
9300 VectorizedLoads.insert_range(Slice);
9302 if (Cnt == StartIdx)
9303 StartIdx += NumElts;
9306 for (LoadInst *LI : Loads) {
9307 if (!VectorizedLoads.contains(LI))
9308 NonVectorized.push_back(LI);
9312 auto ProcessGatheredLoads =
9315 bool Final =
false) {
9317 for (
ArrayRef<std::pair<LoadInst *, int64_t>> LoadsDists :
9319 if (LoadsDists.size() <= 1) {
9320 NonVectorized.
push_back(LoadsDists.back().first);
9328 unsigned MaxConsecutiveDistance = 0;
9329 unsigned CurrentConsecutiveDist = 1;
9330 int64_t LastDist = LocalLoadsDists.front().second;
9331 bool AllowMaskedGather = IsMaskedGatherSupported(OriginalLoads);
9332 for (
const std::pair<LoadInst *, int64_t> &L : LocalLoadsDists) {
9335 assert(LastDist >=
L.second &&
9336 "Expected first distance always not less than second");
9337 if (
static_cast<uint64_t>(LastDist -
L.second) ==
9338 CurrentConsecutiveDist) {
9339 ++CurrentConsecutiveDist;
9340 MaxConsecutiveDistance =
9341 std::max(MaxConsecutiveDistance, CurrentConsecutiveDist);
9345 if (!AllowMaskedGather && CurrentConsecutiveDist == 1 &&
9348 CurrentConsecutiveDist = 1;
9349 LastDist =
L.second;
9352 if (Loads.
size() <= 1)
9354 if (AllowMaskedGather)
9355 MaxConsecutiveDistance = Loads.
size();
9356 else if (MaxConsecutiveDistance < 2)
9361 GetVectorizedRanges(Loads, VectorizedLoads, SortedNonVectorized,
9362 Final, MaxConsecutiveDistance);
9364 OriginalLoads.size() == Loads.
size() &&
9365 MaxConsecutiveDistance == Loads.
size() &&
9370 VectorizedLoads.
clear();
9374 GetVectorizedRanges(OriginalLoads, VectorizedLoads,
9375 UnsortedNonVectorized, Final,
9376 OriginalLoads.size());
9377 if (SortedNonVectorized.
size() >= UnsortedNonVectorized.
size()) {
9378 SortedNonVectorized.
swap(UnsortedNonVectorized);
9379 Results.swap(UnsortedResults);
9384 << Slice.
size() <<
")\n");
9386 for (
Value *L : Slice)
9394 unsigned MaxVF = Slice.size();
9395 unsigned UserMaxVF = 0;
9396 unsigned InterleaveFactor = 0;
9401 std::optional<unsigned> InterleavedLoadsDistance = 0;
9403 std::optional<unsigned> CommonVF = 0;
9404 DenseMap<const TreeEntry *, unsigned> EntryToPosition;
9405 SmallPtrSet<const TreeEntry *, 8> DeinterleavedNodes;
9406 for (
auto [Idx, V] :
enumerate(Slice)) {
9407 for (
const TreeEntry *
E : ValueToGatherNodes.at(V)) {
9408 UserMaxVF = std::max<unsigned>(UserMaxVF,
E->Scalars.size());
9411 UserMaxVF = std::max<unsigned>(UserMaxVF, Idx - Pos + 1);
9413 if (*CommonVF == 0) {
9414 CommonVF =
E->Scalars.size();
9417 if (*CommonVF !=
E->Scalars.size())
9421 if (Pos != Idx && InterleavedLoadsDistance) {
9424 if (isa<Constant>(V))
9426 if (isVectorized(V))
9428 const auto &Nodes = ValueToGatherNodes.at(V);
9429 return (Nodes.size() != 1 || !Nodes.contains(E)) &&
9430 !is_contained(Slice, V);
9432 InterleavedLoadsDistance.reset();
9436 if (*InterleavedLoadsDistance == 0) {
9437 InterleavedLoadsDistance = Idx - Pos;
9440 if ((Idx - Pos) % *InterleavedLoadsDistance != 0 ||
9441 (Idx - Pos) / *InterleavedLoadsDistance < Order)
9442 InterleavedLoadsDistance.reset();
9443 Order = (Idx - Pos) / InterleavedLoadsDistance.value_or(1);
9447 DeinterleavedNodes.
clear();
9449 if (InterleavedLoadsDistance.value_or(0) > 1 &&
9450 CommonVF.value_or(0) != 0) {
9451 InterleaveFactor =
bit_ceil(*InterleavedLoadsDistance);
9452 unsigned VF = *CommonVF;
9457 if (InterleaveFactor <= Slice.size() &&
9458 TTI.isLegalInterleavedAccessType(
9464 ->getPointerAddressSpace()) &&
9467 UserMaxVF = InterleaveFactor * VF;
9469 InterleaveFactor = 0;
9474 unsigned ConsecutiveNodesSize = 0;
9475 if (!LoadEntriesToVectorize.empty() && InterleaveFactor == 0 &&
9476 any_of(
zip(LoadEntriesToVectorize, LoadSetsToVectorize),
9477 [&, Slice = Slice](
const auto &
P) {
9479 return std::get<1>(
P).contains(V);
9481 if (It == Slice.end())
9483 const TreeEntry &
TE =
9484 *VectorizableTree[std::get<0>(
P)];
9490 VL, VL.
front(), Order, PointerOps, SPtrInfo);
9495 ConsecutiveNodesSize += VL.
size();
9496 size_t Start = std::distance(Slice.begin(), It);
9497 size_t Sz = Slice.size() -
Start;
9498 return Sz < VL.
size() ||
9499 Slice.slice(Start, VL.
size()) != VL;
9504 if (InterleaveFactor == 0 &&
9506 [&, Slice = Slice](
unsigned Idx) {
9508 SmallVector<Value *> PointerOps;
9509 StridedPtrInfo SPtrInfo;
9510 return canVectorizeLoads(
9511 Slice.slice(Idx * UserMaxVF, UserMaxVF),
9512 Slice[Idx * UserMaxVF], Order, PointerOps,
9513 SPtrInfo) == LoadsState::ScatterVectorize;
9516 if (Slice.size() != ConsecutiveNodesSize)
9517 MaxVF = std::min<unsigned>(MaxVF, UserMaxVF);
9519 for (
unsigned VF = MaxVF; VF >= 2; VF /= 2) {
9520 bool IsVectorized =
true;
9521 for (
unsigned I = 0,
E = Slice.size();
I <
E;
I += VF) {
9523 Slice.slice(
I, std::min(VF,
E -
I));
9528 if (
any_of(
zip(LoadEntriesToVectorize, LoadSetsToVectorize),
9529 [&](
const auto &
P) {
9531 VectorizableTree[std::get<0>(
P)]
9536 unsigned Sz = VectorizableTree.size();
9541 SubSlice.
size() >= InterleaveFactor ? InterleaveFactor : 0);
9542 if (Sz == VectorizableTree.size()) {
9543 IsVectorized =
false;
9546 if (InterleaveFactor > 0) {
9547 VF = 2 * (MaxVF / InterleaveFactor);
9548 InterleaveFactor = 0;
9557 NonVectorized.
append(SortedNonVectorized);
9559 return NonVectorized;
9561 for (
const auto &GLs : GatheredLoads) {
9562 const auto &
Ref = GLs.second;
9564 if (!
Ref.empty() && !NonVectorized.
empty() &&
9567 [](
unsigned S,
ArrayRef<std::pair<LoadInst *, int64_t>> LoadsDists)
9568 ->
unsigned {
return S + LoadsDists.size(); }) !=
9569 NonVectorized.
size() &&
9570 IsMaskedGatherSupported(NonVectorized)) {
9573 for (LoadInst *LI : NonVectorized) {
9581 (void)ProcessGatheredLoads(FinalGatheredLoads,
true);
9585 for (
unsigned Idx : LoadEntriesToVectorize) {
9586 const TreeEntry &
E = *VectorizableTree[Idx];
9589 if (!
E.ReorderIndices.empty()) {
9592 SmallVector<int> ReorderMask;
9596 buildTreeRec(GatheredScalars, 0,
EdgeInfo());
9600 if (
static_cast<unsigned>(*GatheredLoadsEntriesFirst) ==
9601 VectorizableTree.size())
9602 GatheredLoadsEntriesFirst.reset();
9612 bool AllowAlternate) {
9647 std::pair<size_t, size_t> OpVals =
9655 if (CI->isCommutative())
9664 if (ID == Intrinsic::fmuladd)
9665 ID = Intrinsic::fma;
9681 SubKey =
hash_value(Gep->getPointerOperand());
9694 return std::make_pair(
Key, SubKey);
9700 Instruction *AltOp,
const TargetLibraryInfo &TLI);
9706 const unsigned VF,
unsigned MinBW,
9729static std::pair<InstructionCost, InstructionCost>
9741 LibCost =
TTI->getCallInstrCost(
nullptr, VecTy, ArgTys,
CostKind);
9748 FMF = FPCI->getFastMathFlags();
9751 LibCost.isValid() ? LibCost : ScalarLimit);
9753 if (LibCost.isValid()) {
9779 "getVectorOpCost expects an arithmetic op or a vectorizable call.");
9784 auto [IntrCost, LibCost] =
9786 return std::min(IntrCost, LibCost);
9788 return TTI.getArithmeticInstrCost(
I->getOpcode(), VecTy,
CostKind);
9795 return (
static_cast<unsigned>(Ty->getTypeID()) << 16) |
9796 Ty->getScalarSizeInBits();
9801struct PoorThroughputOpCache {
9802 SmallDenseSet<std::pair<unsigned, unsigned>> CheapOpcodes;
9803 SmallDenseSet<std::pair<Intrinsic::ID, unsigned>> CheapIntrinsics;
9806 SmallDenseSet<const Function *> CheapCallees;
9810struct SeedGroupKey {
9811 unsigned Opcode = 0;
9813 StringRef CalleeName;
9815 bool less(
const SeedGroupKey &O)
const {
9816 if (Opcode !=
O.Opcode)
9817 return Opcode <
O.Opcode;
9818 if (IntrID !=
O.IntrID)
9819 return IntrID <
O.IntrID;
9820 return CalleeName <
O.CalleeName;
9824static SeedGroupKey getSeedGroupKey(
const Instruction *
I,
9825 const TargetLibraryInfo &TLI) {
9827 K.Opcode =
I->getOpcode();
9830 if (
const Function *F = CI->getCalledFunction())
9831 K.CalleeName = F->getName();
9841 PoorThroughputOpCache &Cache,
9845 Type *Ty =
I->getType();
9846 if ((Ty->isVectorTy() && !
SLPReVec) || Ty->isAggregateType() ||
9849 auto Analyze = [&]() {
9853 constexpr unsigned MinVF = 2;
9866 return !isValidElementType(Arg->getType(), SLPReVec);
9871 return CheckCached(Cache.CheapIntrinsics.contains(
Key),
9872 [&] { Cache.CheapIntrinsics.insert(Key); });
9874 const Function *Callee = CI->getCalledFunction();
9877 return CheckCached(Cache.CheapCallees.contains(Callee),
9878 [&] { Cache.CheapCallees.insert(Callee); });
9881 return CheckCached(Cache.CheapOpcodes.contains(
Key),
9882 [&] { Cache.CheapOpcodes.insert(Key); });
9889 assert(L &&
"Expected valid loop");
9895 while (L && IsLoopInvariant(L, VL))
9896 L = L->getParentLoop();
9902 assert(L &&
"Expected valid loop");
9905 SmallVector<const Loop *> &Res =
9906 LoopToLoopNest.try_emplace(L).first->getSecond();
9909 SmallVector<const Loop *> LoopNest;
9912 L =
L->getParentLoop();
9944 "Expected extractvalue instruction state.");
9950 for (
Value *V : VL) {
9952 Aggregates.push_back(VL0->getAggregateOperand());
9956 if (
IV->getIndices() != VL0Indices ||
9959 Value *Agg =
IV->getAggregateOperand();
9963 if (AggState && AggState.
getOpcode() == Instruction::Call &&
9989BoUpSLP::TreeEntry::EntryState BoUpSLP::getScalarsVectorizationState(
9991 bool IsScatterVectorizeUserTE,
OrdersType &CurrentOrder,
9993 SmallVectorImpl<int> &ReuseShuffleIndices) {
9995 "Expected instructions with same/alternate opcodes only.");
9997 unsigned ShuffleOrOp =
10000 switch (ShuffleOrOp) {
10001 case Instruction::PHI: {
10004 return TreeEntry::NeedToGather;
10006 for (
Value *V : VL) {
10010 for (
Value *Incoming :
PHI->incoming_values()) {
10012 if (Term &&
Term->isTerminator()) {
10014 <<
"SLP: Need to swizzle PHINodes (terminator use).\n");
10015 return TreeEntry::NeedToGather;
10020 return TreeEntry::Vectorize;
10022 case Instruction::ExtractElement:
10029 Value *
Op = EI->getOperand(0);
10033 return OpI && OpI->isTerminator();
10035 return TreeEntry::NeedToGather;
10037 case Instruction::ExtractValue: {
10038 bool Reuse = canReuseExtract(VL, CurrentOrder);
10044 (!Reuse || !ReuseShuffleIndices.
empty()))
10045 return TreeEntry::NeedToGather;
10046 if (Reuse || !CurrentOrder.empty())
10047 return TreeEntry::Vectorize;
10048 SmallVector<unsigned> Indices;
10050 if (ShuffleOrOp == Instruction::ExtractValue &&
10052 return TreeEntry::Vectorize;
10054 return TreeEntry::NeedToGather;
10056 case Instruction::InsertValue:
10066 return IV && (
IV->getNumIndices() != 1 ||
10069 IV->getOperand(1)->getType()->isVectorTy());
10075 return TreeEntry::NeedToGather;
10077 case Instruction::InsertElement: {
10081 for (
Value *V : VL) {
10085 <<
"SLP: Gather of insertelement/insertvalue/poison vector.\n");
10086 return TreeEntry::NeedToGather;
10090 "Non-constant or undef index?");
10094 return !SourceVectors.contains(V);
10098 dbgs() <<
"SLP: Gather of insertelement/insertvalue vectors with "
10099 "different source vectors.\n");
10100 return TreeEntry::NeedToGather;
10105 return SourceVectors.contains(V) && !
V->hasOneUse();
10108 "Only supported by REVEC or InsertValue.");
10110 dbgs() <<
"SLP: Gather of insertelement/insertvalue vectors with "
10111 "multiple uses.\n");
10112 return TreeEntry::NeedToGather;
10115 return TreeEntry::Vectorize;
10117 case Instruction::Load: {
10124 auto IsGatheredNode = [&]() {
10125 if (!GatheredLoadsEntriesFirst)
10130 return any_of(getTreeEntries(V), [&](
const TreeEntry *TE) {
10131 return TE->Idx >= *GatheredLoadsEntriesFirst;
10137 return TreeEntry::Vectorize;
10139 if (!IsGraphTransformMode && VectorizableTree.size() > 1) {
10141 LoadEntriesToVectorize.insert(VectorizableTree.size());
10142 return TreeEntry::NeedToGather;
10144 return IsGatheredNode() ? TreeEntry::NeedToGather
10145 : TreeEntry::CompressVectorize;
10147 if (!IsGraphTransformMode && VectorizableTree.size() > 1) {
10149 LoadEntriesToVectorize.insert(VectorizableTree.size());
10150 return TreeEntry::NeedToGather;
10152 return IsGatheredNode() ? TreeEntry::NeedToGather
10153 : TreeEntry::ScatterVectorize;
10155 if (!IsGraphTransformMode && VectorizableTree.size() > 1) {
10157 LoadEntriesToVectorize.insert(VectorizableTree.size());
10158 return TreeEntry::NeedToGather;
10160 return IsGatheredNode() ? TreeEntry::NeedToGather
10161 : TreeEntry::StridedVectorize;
10163 if (!IsGraphTransformMode && VectorizableTree.size() > 1) {
10165 LoadEntriesToVectorize.insert(VectorizableTree.size());
10166 return TreeEntry::NeedToGather;
10168 return IsGatheredNode() ? TreeEntry::NeedToGather
10169 : TreeEntry::BlendedLoadVectorize;
10173 if (DL->getTypeSizeInBits(ScalarTy) !=
10174 DL->getTypeAllocSizeInBits(ScalarTy))
10175 LLVM_DEBUG(
dbgs() <<
"SLP: Gathering loads of non-packed type.\n");
10178 return !LI || !LI->isSimple();
10182 LLVM_DEBUG(
dbgs() <<
"SLP: Gathering non-consecutive loads.\n");
10185 return TreeEntry::NeedToGather;
10189 case Instruction::ZExt:
10190 case Instruction::SExt:
10191 case Instruction::FPToUI:
10192 case Instruction::FPToSI:
10193 case Instruction::FPExt:
10194 case Instruction::PtrToInt:
10195 case Instruction::PtrToAddr:
10196 case Instruction::IntToPtr:
10197 case Instruction::SIToFP:
10198 case Instruction::UIToFP:
10199 case Instruction::Trunc:
10200 case Instruction::FPTrunc:
10201 case Instruction::BitCast: {
10203 for (
Value *V : VL) {
10209 dbgs() <<
"SLP: Gathering casts with different src types.\n");
10210 return TreeEntry::NeedToGather;
10213 return TreeEntry::Vectorize;
10215 case Instruction::ICmp:
10216 case Instruction::FCmp: {
10221 for (
Value *V : VL) {
10225 if ((
Cmp->getPredicate() != P0 &&
Cmp->getPredicate() != SwapP0 &&
10227 Cmp->getOperand(0)->getType() != ComparedTy) {
10228 LLVM_DEBUG(
dbgs() <<
"SLP: Gathering cmp with different predicate.\n");
10229 return TreeEntry::NeedToGather;
10232 return TreeEntry::Vectorize;
10234 case Instruction::Select:
10236 SmallPtrSet<Type *, 4> CondTypes;
10237 for (
Value *V : VL) {
10244 if (CondTypes.
size() > 1) {
10247 <<
"SLP: Gathering select with different condition types.\n");
10248 return TreeEntry::NeedToGather;
10252 case Instruction::FNeg:
10253 case Instruction::Add:
10254 case Instruction::FAdd:
10255 case Instruction::Sub:
10256 case Instruction::FSub:
10257 case Instruction::Mul:
10258 case Instruction::FMul:
10259 case Instruction::UDiv:
10260 case Instruction::SDiv:
10261 case Instruction::FDiv:
10262 case Instruction::URem:
10263 case Instruction::SRem:
10264 case Instruction::FRem:
10265 case Instruction::Shl:
10266 case Instruction::LShr:
10267 case Instruction::AShr:
10268 case Instruction::And:
10269 case Instruction::Or:
10270 case Instruction::Xor:
10271 case Instruction::Freeze:
10273 TTI->isFPVectorizationPotentiallyUnsafe() &&
any_of(VL, [](
Value *V) {
10275 return I &&
I->isBinaryOp() && !
I->isFast();
10277 return TreeEntry::NeedToGather;
10278 return TreeEntry::Vectorize;
10279 case Instruction::GetElementPtr: {
10281 for (
Value *V : VL) {
10285 if (
I->getNumOperands() != 2) {
10286 LLVM_DEBUG(
dbgs() <<
"SLP: not-vectorizable GEP (nested indexes).\n");
10287 return TreeEntry::NeedToGather;
10294 for (
Value *V : VL) {
10298 Type *CurTy =
GEP->getSourceElementType();
10299 if (Ty0 != CurTy) {
10300 LLVM_DEBUG(
dbgs() <<
"SLP: not-vectorizable GEP (different types).\n");
10301 return TreeEntry::NeedToGather;
10307 for (
Value *V : VL) {
10311 auto *
Op =
I->getOperand(1);
10313 (
Op->getType() != Ty1 &&
10315 Op->getType()->getScalarSizeInBits() >
10316 DL->getIndexSizeInBits(
10317 V->getType()->getPointerAddressSpace())))) {
10319 dbgs() <<
"SLP: not-vectorizable GEP (non-constant indexes).\n");
10320 return TreeEntry::NeedToGather;
10324 return TreeEntry::Vectorize;
10326 case Instruction::Store: {
10328 llvm::Type *ScalarTy =
cast<StoreInst>(VL0)->getValueOperand()->getType();
10331 if (DL->getTypeSizeInBits(ScalarTy) !=
10332 DL->getTypeAllocSizeInBits(ScalarTy)) {
10333 LLVM_DEBUG(
dbgs() <<
"SLP: Gathering stores of non-packed type.\n");
10334 return TreeEntry::NeedToGather;
10338 for (
Value *V : VL) {
10340 if (!
SI->isSimple()) {
10342 return TreeEntry::NeedToGather;
10351 if (CurrentOrder.empty()) {
10352 Ptr0 = PointerOps.
front();
10353 PtrN = PointerOps.
back();
10355 Ptr0 = PointerOps[CurrentOrder.front()];
10356 PtrN = PointerOps[CurrentOrder.back()];
10359 std::optional<int64_t> Dist =
10362 if (
static_cast<uint64_t>(*Dist) == VL.size() - 1)
10363 return TreeEntry::Vectorize;
10366 CurrentOrder, *Dist, Ptr0, SPtrInfo))
10367 return TreeEntry::StridedVectorize;
10370 FixedVectorType *StoreVecTy =
nullptr;
10373 CommonAlignment, ReuseShuffleIndices,
10375 SPtrInfo.Ty = StoreVecTy;
10376 return TreeEntry::ExpandVectorize;
10381 return TreeEntry::NeedToGather;
10383 case Instruction::Call: {
10385 TTI->isFPVectorizationPotentiallyUnsafe() &&
any_of(VL, [](
Value *V) {
10387 return FPOp && !FPOp->isFast();
10389 return TreeEntry::NeedToGather;
10399 Function *VecFunc = VFDatabase(*CI).getVectorizedFunction(Shape);
10403 return TreeEntry::NeedToGather;
10407 LLVM_DEBUG(
dbgs() <<
"SLP: Struct-returning calls have non-extractvalue "
10409 return TreeEntry::NeedToGather;
10412 unsigned NumArgs = CI->
arg_size();
10413 SmallVector<Value *, 4> ScalarArgs(NumArgs,
nullptr);
10414 for (
unsigned J = 0; J != NumArgs; ++J)
10417 for (
Value *V : VL) {
10431 VecFunc != VFDatabase(*CI2).getVectorizedFunction(Shape)) ||
10433 LLVM_DEBUG(
dbgs() <<
"SLP: mismatched calls:" << *CI <<
"!=" << *V
10435 return TreeEntry::NeedToGather;
10439 for (
unsigned J = 0; J != NumArgs; ++J) {
10442 if (ScalarArgs[J] != A1J) {
10444 <<
"SLP: mismatched arguments in call:" << *CI
10445 <<
" argument " << ScalarArgs[J] <<
"!=" << A1J <<
"\n");
10446 return TreeEntry::NeedToGather;
10455 LLVM_DEBUG(
dbgs() <<
"SLP: mismatched bundle operands in calls:" << *CI
10456 <<
"!=" << *V <<
'\n');
10457 return TreeEntry::NeedToGather;
10463 auto VecCallCosts =
10465 if (!VecCallCosts.first.isValid() && !VecCallCosts.second.isValid())
10466 return TreeEntry::NeedToGather;
10468 return TreeEntry::Vectorize;
10470 case Instruction::ShuffleVector: {
10474 return TreeEntry::Vectorize;
10477 LLVM_DEBUG(
dbgs() <<
"SLP: ShuffleVector are not vectorized.\n");
10478 return TreeEntry::NeedToGather;
10481 return TreeEntry::Vectorize;
10485 return TreeEntry::NeedToGather;
10494 PHINode *Main =
nullptr;
10499 PHIHandler() =
delete;
10501 : DT(DT), Main(Main), Phis(Phis),
10502 Operands(Main->getNumIncomingValues(),
10504 void buildOperands() {
10505 constexpr unsigned FastLimit = 4;
10514 for (
auto [Idx, V] :
enumerate(Phis)) {
10518 "Expected isa instruction or poison value.");
10522 if (
P->getIncomingBlock(
I) == InBB)
10525 Operands[
I][Idx] =
P->getIncomingValueForBlock(InBB);
10530 SmallMapVector<BasicBlock *, SmallVector<unsigned>, 4>
10540 for (
auto [Idx, V] :
enumerate(Phis)) {
10555 auto *It = Blocks.
find(InBB);
10556 if (It == Blocks.
end())
10558 Operands[It->second.front()][Idx] =
P->getIncomingValue(
I);
10561 for (
const auto &
P : Blocks) {
10562 ArrayRef<unsigned> IncomingValues =
P.second;
10563 if (IncomingValues.
size() <= 1)
10566 for (
unsigned I : IncomingValues) {
10568 [&](
const auto &
Data) {
10569 return !
Data.value() ||
10572 "Expected empty operands list.");
10586static std::pair<Instruction *, Instruction *>
10590 for (
Value *V : VL) {
10600 if (MainOp->
getOpcode() ==
I->getOpcode()) {
10619 "Expected different main and alt instructions.");
10620 return std::make_pair(MainOp, AltOp);
10635 const BoUpSLP &R,
bool BuildGatherOnly =
true) {
10639 ReuseShuffleIndices.
clear();
10645 for (
Value *V : VL) {
10662 bool RequireScheduling = S && S.
getOpcode() != Instruction::PHI &&
10669 bool AreAllValuesNonConst = UniquePositions.
size() == UniqueValues.
size();
10671 if (RequireScheduling) {
10675 assert(EndIt != UniqueValues.
rend() &&
"Expected at least one non-poison.");
10676 UniqueValues.
erase(EndIt.base(), UniqueValues.
end());
10678 unsigned NumUniqueScalarValues = UniqueValues.
size();
10679 if (NumUniqueScalarValues == VL.
size()) {
10680 ReuseShuffleIndices.
clear();
10688 constexpr unsigned SmallVecWidth = 4;
10689 constexpr unsigned SmallVecUniqueThreshold = 3;
10690 if (VL.
size() == SmallVecWidth &&
10691 NumUniqueScalarValues == SmallVecUniqueThreshold && !BuildGatherOnly &&
10692 !(S && (S.
getOpcode() == Instruction::Load ||
10695 ReuseShuffleIndices.
clear();
10701 auto EstimatePackPlusShuffleVsInserts = [&]() {
10703 if (UniquePositions.
size() == 1 &&
10704 (NumUniqueScalarValues == 1 ||
10706 return std::make_pair(
false,
false);
10710 constexpr unsigned MinVLForConstGatherCheck = 4;
10711 if (BuildGatherOnly && VL.
size() > MinVLForConstGatherCheck &&
10714 UniquePositions.
size() * 2 < NumUniqueScalarValues)
10715 return std::make_pair(
false,
false);
10722 PointerOps, SPtrInfo);
10737 bool IsRootOperand =
10738 UserTreeIdx.
UserTE && UserTreeIdx.
UserTE->Idx == 0 && !BuildGatherOnly;
10739 if (IsRootOperand) {
10740 if (S && S.
getOpcode() == Instruction::Load) {
10741 bool UseOrig = (CheckLoads(UniqueValues,
true) &&
10742 CheckLoads(VL,
false)) ||
10744 ReuseShuffleIndices, ReuseShuffleIndices.
size());
10745 return std::make_pair(
true, UseOrig);
10747 return std::make_pair(
true, !RequireScheduling);
10750 for (
auto [Idx, Val] :
enumerate(ReuseShuffleIndices))
10752 DemandedElts.
setBit(Idx);
10755 auto *UniquesVecTy =
10758 const unsigned UniquesNumParts =
10762 if (!RequireScheduling) {
10763 if (VL.
size() / NumUniqueScalarValues == 1 &&
10764 (NumParts <= 1 || UniquesNumParts >= NumParts))
10765 return std::make_pair(
true,
true);
10768 if (S && S.
getOpcode() == Instruction::PHI && NumUniqueScalarValues > 1 &&
10769 UniquesNumParts <= NumParts)
10770 return std::make_pair(
true,
false);
10785 if (S && !BuildGatherOnly) {
10786 bool HasOneDup = S.
getOpcode() != Instruction::Load &&
10787 NumUniqueScalarValues + 1 == VL.
size();
10788 bool MostlyUnique = NumUniqueScalarValues * 2 > VL.
size();
10789 bool IsHalfUniqueValues =
10790 NumUniqueScalarValues * 2 == VL.
size() &&
10791 (S.
getOpcode() == Instruction::GetElementPtr ||
10794 NumParts * (VL.
size() > SmallVecWidth ? 1 : 2);
10796 ((MostlyUnique || IsHalfUniqueValues) && ReusesCost >
CostThreshold))
10797 return std::make_pair(
true,
true);
10802 if (S && S.
getOpcode() == Instruction::Load) {
10803 bool UniquesVectorized =
10804 CheckLoads(UniqueValues,
false);
10805 if (UniquesVectorized || CheckLoads(VL,
false))
10806 return std::make_pair(
true, !UniquesVectorized);
10808 bool CanSkipBVCost =
10809 (!BuildGatherOnly && !RequireScheduling) || R.hasSameNode(S, VL);
10816 CostKind, AreAllValuesNonConst, VL);
10818 for (
const auto [Idx, V] :
enumerate(UniqueValues))
10820 UniquesDemandedElts.
clearBit(Idx);
10825 UniquesDemandedElts,
true,
10827 AreAllValuesNonConst, UniqueValues);
10828 UniquesCost += ReusesCost;
10829 if (UniquesCost <= InsertsCost) {
10833 if (S && S.
getOpcode() != Instruction::Load) {
10836 unsigned MinVF = R.getMinVF(EltBits);
10837 auto RegWidth = [&](
unsigned N) {
10844 auto HasExtraReshuffle = [&]() {
10845 if (BuildGatherOnly)
10847 unsigned NumDupColumns = 0;
10848 for (
unsigned OpIdx :
10851 for (
Value *V : VL) {
10861 if (!
I || OpIdx >=
I->getNumOperands())
10863 Op =
I->getOperand(OpIdx);
10870 if (NumDupColumns > 1)
10875 return std::make_pair(
true, RegWidth(NumUniqueScalarValues) >=
10876 RegWidth(VL.
size()) &&
10877 !HasExtraReshuffle());
10879 return std::make_pair(
true,
false);
10883 (R.getTreeSize() == 0 && R.isReductionTree() &&
10885 return std::make_pair(S && (!S.
isAltShuffle() || !BuildGatherOnly),
10889 bool KeepOriginal = !BuildGatherOnly && !RequireScheduling;
10890 return std::make_pair(KeepOriginal, KeepOriginal);
10893 const auto [PackProfitable, UseOriginal] = EstimatePackPlusShuffleVsInserts();
10895 if (PackProfitable) {
10898 ReuseShuffleIndices.
clear();
10902 VL = std::move(UniqueValues);
10909 ReuseShuffleIndices.
clear();
10918 constexpr unsigned SmallNodeSize = 4;
10919 if (VL.
size() <= SmallNodeSize || TTI->preferAlternateOpcodeVectorization() ||
10926 for (TreeEntry *E : getSplitTreeEntries(LocalState.
getMainOp())) {
10927 if (E->isSame(VL)) {
10947 Op1Indices.
set(Idx);
10957 Op1Indices.
set(Idx);
10964 unsigned Opcode0 = LocalState.
getOpcode();
10971 if (UOp1.
size() <= 1 || UOp2.
size() <= 1 ||
10972 TTI->isLegalAltInstr(VecTy, Opcode0, Opcode1, OpcodeMask))
10974 unsigned Op1Cnt = 0, Op2Cnt = Op1.
size();
10976 if (Op1Indices.
test(Idx)) {
10977 ReorderIndices[Op1Cnt] = Idx;
10980 ReorderIndices[Op2Cnt] = Idx;
10985 ReorderIndices.
clear();
10996 if (!ReorderIndices.
empty())
10998 unsigned NumParts = TTI->getNumberOfParts(VecTy);
11003 if (NumParts >= VL.
size())
11011 if (!LocalState.
isCmpOp() && NumParts <= 1 &&
11012 (Mask.empty() || InsertCost >= NewShuffleCost))
11022 TTI->getArithmeticInstrCost(Opcode0, VecTy, CostKind) +
11023 TTI->getArithmeticInstrCost(Opcode1, VecTy, CostKind);
11028 OriginalMask[Idx] = Idx + (Op1Indices.
test(Idx) ? 0 : VL.
size());
11032 CostKind, OriginalMask);
11034 TTI->getArithmeticInstrCost(Opcode0, Op1VecTy, CostKind) +
11035 TTI->getArithmeticInstrCost(Opcode1, Op2VecTy, CostKind);
11037 NewVecOpsCost + InsertCost +
11038 (!VectorizableTree.empty() &&
getRootNode().hasState() &&
11043 if (NewCost >= OriginalCost)
11053class InstructionsCompatibilityAnalysis {
11058 unsigned MainOpcode = 0;
11062 bool AbsorbCopyableFMulOrFAdds =
false;
11066 static bool isSupportedOpcode(
const unsigned Opcode) {
11067 return Opcode == Instruction::Add || Opcode == Instruction::Sub ||
11068 Opcode == Instruction::Mul || Opcode == Instruction::AShr ||
11069 Opcode == Instruction::LShr || Opcode == Instruction::Shl ||
11070 Opcode == Instruction::SDiv || Opcode == Instruction::UDiv ||
11071 Opcode == Instruction::And || Opcode == Instruction::Or ||
11072 Opcode == Instruction::Xor || Opcode == Instruction::FAdd ||
11073 Opcode == Instruction::FSub || Opcode == Instruction::FMul ||
11074 Opcode == Instruction::FDiv;
11097 auto IsSupportedInstruction = [&](
Instruction *
I,
bool AnyUndef) {
11098 if (AnyUndef && (
I->isIntDivRem() ||
I->isFPDivRem() ||
isa<CallInst>(
I)))
11100 return I && isSupportedMainOp(
I) &&
11105 SmallDenseSet<Value *, 8>
Operands;
11106 SmallMapVector<unsigned, SmallVector<Instruction *>, 4> Candidates;
11107 bool AnyUndef =
false;
11108 for (
Value *V : VL) {
11116 if (Candidates.
empty()) {
11117 Candidates.
try_emplace(
I->getOpcode()).first->second.push_back(
I);
11122 if (Parent ==
I->getParent()) {
11123 Candidates.
try_emplace(
I->getOpcode()).first->second.push_back(
I);
11124 Operands.insert(
I->op_begin(),
I->op_end());
11127 auto *NodeA = DT.
getNode(Parent);
11128 auto *NodeB = DT.
getNode(
I->getParent());
11129 assert(NodeA &&
"Should only process reachable instructions");
11130 assert(NodeB &&
"Should only process reachable instructions");
11131 assert((NodeA == NodeB) ==
11132 (NodeA->getDFSNumIn() == NodeB->getDFSNumIn()) &&
11133 "Different nodes should have different DFS numbers");
11134 if (NodeA->getDFSNumIn() < NodeB->getDFSNumIn()) {
11135 Candidates.
clear();
11136 Candidates.
try_emplace(
I->getOpcode()).first->second.push_back(
I);
11142 unsigned BestOpcodeNum = 0;
11144 bool UsedOutside =
false;
11145 for (
const auto &
P : Candidates) {
11147 if (UsedOutside && !PUsedOutside)
11149 if (!UsedOutside && PUsedOutside)
11151 if (
P.second.size() < BestOpcodeNum)
11154 if (!PUsedOutside &&
any_of(
P.second, [&](Instruction *
I) {
11155 return Operands.contains(I);
11162 if (
P.second.size() == BestOpcodeNum) {
11163 auto *
I =
P.second.front();
11167 if (MainBOOp0 && MainBOOp0->getOpcode() ==
I->getOpcode() &&
11168 MainBOOp0->getParent() ==
I->getParent())
11170 if (MainBOOp1 && MainBOOp1->getOpcode() ==
I->getOpcode() &&
11171 MainBOOp1->getParent() ==
I->getParent())
11177 (
I->getOpcode() == Instruction::FMul ||
11178 I->getOpcode() == Instruction::FAdd) &&
11179 AbsorbCopyableFMulOrFAdds)
11182 if ((MainOp->
getOpcode() == Instruction::FMul ||
11183 MainOp->
getOpcode() == Instruction::FAdd) &&
11185 !AbsorbCopyableFMulOrFAdds)
11188 UsedOutside = PUsedOutside;
11189 for (Instruction *
I :
P.second) {
11190 if (IsSupportedInstruction(
I, AnyUndef)) {
11192 BestOpcodeNum =
P.second.size();
11202 return I &&
I->getParent() == MainOp->
getParent() &&
11216 Value *selectBestIdempotentValue()
const {
11217 assert(isSupportedMainOp(MainOp) &&
"Unsupported opcode");
11236 if (
I->getOpcode() == Instruction::FMul)
11237 return {
I->getOperand(0),
I->getOperand(1),
11240 return {ConstantFP::get(Ty, 1.0),
I->getOperand(0),
I->getOperand(1)};
11248 assert(isSupportedMainOp(MainOp) &&
"Unsupported opcode");
11249 return {
V, selectBestIdempotentValue()};
11255 SmallVectorImpl<BoUpSLP::ValueList> &
Operands)
const {
11257 unsigned ShuffleOrOp =
11261 switch (ShuffleOrOp) {
11262 case Instruction::PHI: {
11266 PHIHandler Handler(DT, PH, VL);
11267 Handler.buildOperands();
11268 Operands.assign(PH->getNumOperands(), {});
11270 Operands[
I].assign(Handler.getOperands(
I).begin(),
11271 Handler.getOperands(
I).end());
11274 case Instruction::ExtractValue: {
11275 SmallVector<unsigned> Indices;
11284 case Instruction::ExtractElement:
11289 case Instruction::InsertValue:
11290 case Instruction::InsertElement:
11295 Ops[Idx] =
IE->getOperand(OpIdx);
11298 case Instruction::Load:
11306 Op = LI->getPointerOperand();
11309 case Instruction::ZExt:
11310 case Instruction::SExt:
11311 case Instruction::FPToUI:
11312 case Instruction::FPToSI:
11313 case Instruction::FPExt:
11314 case Instruction::PtrToInt:
11315 case Instruction::PtrToAddr:
11316 case Instruction::IntToPtr:
11317 case Instruction::SIToFP:
11318 case Instruction::UIToFP:
11319 case Instruction::Trunc:
11320 case Instruction::FPTrunc:
11321 case Instruction::BitCast:
11322 case Instruction::ICmp:
11323 case Instruction::FCmp:
11324 case Instruction::FNeg:
11325 case Instruction::Add:
11326 case Instruction::FAdd:
11327 case Instruction::Sub:
11328 case Instruction::FSub:
11329 case Instruction::Mul:
11330 case Instruction::FMul:
11331 case Instruction::UDiv:
11332 case Instruction::SDiv:
11333 case Instruction::FDiv:
11334 case Instruction::URem:
11335 case Instruction::SRem:
11336 case Instruction::FRem:
11337 case Instruction::Shl:
11338 case Instruction::LShr:
11339 case Instruction::AShr:
11340 case Instruction::And:
11341 case Instruction::Or:
11342 case Instruction::Xor:
11343 case Instruction::Freeze:
11344 case Instruction::Store:
11345 case Instruction::ShuffleVector:
11356 Ops[Idx] = ConvertedOps[OpIdx];
11359 case Instruction::Select:
11374 Operands[1][Idx] = ConstantInt::get(
I->getType(), 1);
11375 Operands[2][Idx] = ConstantInt::getNullValue(
I->getType());
11380 Ops[Idx] = ConvertedOps[OpIdx];
11383 case Instruction::GetElementPtr: {
11390 const unsigned IndexIdx = 1;
11396 return !
GEP || VL0Ty ==
GEP->getOperand(IndexIdx)->getType();
11400 ->getPointerOperandType()
11401 ->getScalarType());
11406 Operands[1][Idx] = ConstantInt::getNullValue(Ty);
11410 auto *
Op =
GEP->getOperand(IndexIdx);
11413 CI, Ty, CI->getValue().isSignBitSet(),
DL)
11418 case Instruction::Call: {
11425 for (
Value *V : VL) {
11427 Ops.push_back(
I ?
I->getOperand(Idx)
11446 const InstructionsState &S,
11447 const InstructionsState &CopyableS) {
11456 const bool IsAltCommutative =
11460 buildOriginalOperands(S, SMain,
Ops);
11462 if (
Ops.size() != 2)
11474 auto *I = dyn_cast<Instruction>(V);
11475 return I && I->getOpcode() == SMainOpI->getOpcode();
11479 for (
Value *V : VL) {
11481 if (!
I ||
I == SMain)
11484 if (MatchingOp != SMain)
11487 buildOriginalOperands(S,
I, VOps);
11488 Operands.insert(
I->op_begin(),
I->op_end());
11490 "Expected binary operations only.");
11491 if (CheckOperands(VOps[0][0],
Ops[0][0]) ||
11492 CheckOperands(VOps[1][0],
Ops[1][0]) ||
11493 (IsCommutative && (CheckOperands(VOps[0][0],
Ops[1][0]) ||
11494 CheckOperands(VOps[1][0],
Ops[0][0])))) {
11501 buildOriginalOperands(S, MainOp, MainOps);
11503 auto BuildFirstOperandCandidates =
11504 [&](SmallVectorImpl<std::pair<Value *, Value *>> &Candidates,
11506 bool IsCommutative) {
11512 auto BuildSecondOperandCandidates =
11513 [&](SmallVectorImpl<std::pair<Value *, Value *>> &Candidates,
11515 Value *Op1,
bool IsCommutative) {
11516 if (PrevBestIdx != 1)
11518 if (PrevBestIdx != 0 && IsCommutative)
11522 auto FindBestCandidate =
11525 auto Res =
R.findBestRootPair(Candidates);
11526 Score = Res.second;
11529 isConstant(Candidates[Res.first.value_or(0)].first) &&
11530 isConstant(Candidates[Res.first.value_or(0)].second);
11534 for (
const auto [Idx,
P] :
enumerate(Candidates)) {
11536 P.second ==
P.first) {
11539 Score =
isa<LoadInst>(Candidates[Res.first.value_or(0)].first)
11549 for (
Value *V : VL) {
11555 buildOriginalOperands(S,
I == SMain ? MainOp :
I, VOps);
11557 getOperands(CopyableS,
I == MainOp ? SMain :
I);
11558 if (CopyableOps.
size() == VOps.
size() &&
11559 all_of(
zip(CopyableOps, VOps), [&](
const auto &
P) {
11560 return std::get<0>(
P) == std::get<1>(
P)[0];
11564 BuildFirstOperandCandidates(Candidates, MainOps, CopyableOps[0],
11565 CopyableOps[1], IsMainCommutative);
11566 const unsigned OpSize = Candidates.
size();
11569 const bool IsCommutativeInst =
11570 (MatchingOp == SMain ? IsCommutative : IsAltCommutative) ||
11579 Operands.insert(
I->op_begin(),
I->op_end());
11580 BuildFirstOperandCandidates(Candidates,
Ops, VOps[0][0], VOps[1][0],
11581 IsCommutativeInst);
11584 std::optional<int> BestOp =
11585 FindBestCandidate(Candidates, IsBestConst, Score);
11586 const bool IsOriginalBetter =
11587 static_cast<unsigned>(BestOp.value_or(OpSize)) >= OpSize;
11588 Candidates.
clear();
11589 BuildSecondOperandCandidates(
11590 Candidates, MainOps, IsOriginalBetter ? -1 : *BestOp, CopyableOps[0],
11591 CopyableOps[1], IsMainCommutative);
11592 const unsigned SecondOpSize = Candidates.
size();
11593 BuildSecondOperandCandidates(
11595 IsOriginalBetter ? BestOp.value_or(OpSize - 1) - OpSize : -1,
11596 VOps[0][0], VOps[1][0], IsCommutativeInst);
11597 bool IsSecondBestConst;
11599 std::optional<int> SecondBestOp =
11600 FindBestCandidate(Candidates, IsSecondBestConst, SecondScore);
11602 if (!BestOp && !SecondBestOp)
11605 const bool IsSecondOriginalBetter =
11606 static_cast<unsigned>(SecondBestOp.value_or(SecondOpSize)) >=
11608 if (IsOriginalBetter && IsSecondOriginalBetter)
11612 if (!BestOp && IsSecondOriginalBetter)
11616 if (!SecondBestOp && IsOriginalBetter)
11620 if (!IsOriginalBetter && IsBestConst && IsSecondOriginalBetter &&
11621 !IsSecondBestConst)
11625 if (BestOp && IsOriginalBetter && !IsBestConst &&
11626 !IsSecondOriginalBetter && IsSecondBestConst)
11629 if (((Score > SecondScore ||
11631 Score == SecondScore)) &&
11632 IsOriginalBetter) ||
11633 (IsSecondOriginalBetter &&
11634 (SecondScore > Score ||
11636 Score == SecondScore))))
11643 InstructionsCompatibilityAnalysis(DominatorTree &DT,
const DataLayout &
DL,
11644 const TargetTransformInfo &
TTI,
11645 const TargetLibraryInfo &TLI)
11650 bool WithProfitabilityCheck =
false,
11651 bool SkipSameCodeCheck =
false) {
11652 InstructionsState S = (SkipSameCodeCheck || !
allSameBlock(VL))
11665 return (ZExt && ZExt->getSrcTy()->isIntegerTy(1)) ||
11669 return InstructionsState(SelectOp, SelectOp);
11676 SmallBitVector OpcodeMask(
11687 I->getOpcode() == Instruction::Shl);
11694 findAndSetMainInstruction(VL, R);
11697 InstructionsState OrigS = S;
11698 S = InstructionsState(MainOp, MainOp,
true);
11699 if (OrigS && !isCopyablePreferable(VL, R, OrigS, S))
11701 if (!WithProfitabilityCheck)
11716 unsigned CopyableNum =
11722 AbsorbCopyableFMulOrFAdds)
11725 auto BuildCandidates =
11726 [](SmallVectorImpl<std::pair<Value *, Value *>> &Candidates,
Value *
V1,
11732 if (I1 && I2 &&
I1->getOpcode() == I2->getOpcode() &&
11733 I1->getParent() != I2->getParent())
11737 if (VL.
size() == 2) {
11740 if (MainOpcode == Instruction::Call)
11746 bool Res = !Candidates1.
empty() && !Candidates2.
empty() &&
11747 R.findBestRootPair(Candidates1).first &&
11748 R.findBestRootPair(Candidates2).first;
11750 Candidates1.
clear();
11751 Candidates2.
clear();
11754 Res = !Candidates1.
empty() && !Candidates2.
empty() &&
11755 R.findBestRootPair(Candidates1).first &&
11756 R.findBestRootPair(Candidates2).first;
11764 switch (MainOpcode) {
11765 case Instruction::Add:
11766 case Instruction::Sub:
11767 case Instruction::Mul:
11768 case Instruction::AShr:
11769 case Instruction::LShr:
11770 case Instruction::Shl:
11771 case Instruction::SDiv:
11772 case Instruction::UDiv:
11773 case Instruction::And:
11774 case Instruction::Or:
11775 case Instruction::Xor:
11776 case Instruction::FAdd:
11777 case Instruction::FMul:
11778 case Instruction::FSub:
11779 case Instruction::FDiv:
11786 if (VectorCost > ScalarCost)
11794 "Unexpected number of operands!");
11795 if (CopyableNum < VL.
size() / 2)
11798 const unsigned Limit = VL.
size() / 24;
11799 if ((CopyableNum >= VL.
size() - Limit ||
11800 (CopyableNum >= VL.
size() - 1 && VL.
size() > 4) ||
11809 Value *BestFrontOp =
nullptr;
11831 const unsigned BestOpcode = BestLHS->getOpcode();
11836 if (OpRI->getOpcode() == BestOpcode)
11856 constexpr unsigned Limit = 4;
11857 if (
Operands.front().size() >= Limit) {
11858 SmallDenseMap<const Value *, unsigned>
Counters;
11866 return C.second == 1;
11872 InstructionsCompatibilityAnalysis
Analysis(DT,
DL,
TTI, TLI);
11873 InstructionsState OpS =
Analysis.buildInstructionsState(
Ops, R);
11876 unsigned CopyableNum =
11878 return CopyableNum <= VL.
size() / 2;
11896 assert(S &&
"Invalid state!");
11904 if (MainOpcode == Instruction::ExtractElement) {
11913 const unsigned NumMainOpOperands =
11915 const bool IsCommutative =
11917 Operands.assign(NumMainOpOperands,
11922 for (
auto [OperandIdx, Operand] :
enumerate(OperandsForValue))
11923 Operands[OperandIdx][Idx] = Operand;
11936 auto CanSwap = [&](
Value *
V) {
11946 auto SwappableLane = [&](
Value *
V) {
11957 unsigned FwdCount = 0;
11958 unsigned RevCount = 0;
11960 SmallMapVector<std::pair<unsigned, unsigned>, PairInfo, 8> PairCounts;
11961 SmallMapVector<unsigned, unsigned, 4> AddendIDCounts;
11962 unsigned MajID0 = 0, MajID1 = 0;
11966 unsigned ID0 =
Operands[0][Idx]->getValueID();
11967 unsigned ID1 =
Operands[1][Idx]->getValueID();
11969 ++AddendIDCounts[
Operands[2][Idx]->getValueID()];
11972 unsigned MinID = std::min(ID0, ID1);
11973 unsigned MaxID = std::max(ID0, ID1);
11975 PairCounts.
try_emplace(std::make_pair(MinID, MaxID));
11976 PairInfo &
Info = It->second;
11985 unsigned BestCount = 0;
11986 for (
const auto &
P : PairCounts) {
11987 const PairInfo &
Info =
P.second;
11989 if (
Total > BestCount) {
11991 if (
Info.FwdCount >=
Info.RevCount) {
11992 MajID0 =
P.first.first;
11993 MajID1 =
P.first.second;
11995 MajID0 =
P.first.second;
11996 MajID1 =
P.first.first;
12005 unsigned MajID2 = 0, Best2 = 0;
12006 for (
const auto &
P : AddendIDCounts) {
12007 if (
P.second > Best2) {
12014 if (!
I ||
I->getOpcode() != Instruction::FAdd ||
12017 unsigned ID1 =
Operands[1][Idx]->getValueID();
12018 unsigned ID2 =
Operands[2][Idx]->getValueID();
12019 unsigned Cur = (ID1 == MajID1) + (ID2 == MajID2);
12020 unsigned Swapped = (ID2 == MajID1) + (ID1 == MajID2);
12032 unsigned LAt0 = 0, LAt1 = 0, TotalNC = 0;
12034 if (!SwappableLane(V))
12037 if (BestCount > 0) {
12038 unsigned ID0 =
Operands[0][Idx]->getValueID();
12039 unsigned ID1 =
Operands[1][Idx]->getValueID();
12040 if (ID0 == MajID1 && ID1 == MajID0 && CanSwap(V))
12049 if (TotalNC > 1 && LAt1 > LAt0 && LAt1 * 2 > TotalNC) {
12051 if (!SwappableLane(V))
12060 buildOriginalOperands(S, VL,
Operands);
12067void BoUpSLP::tryToVectorizeSplatGatheredScalars() {
12068 auto LoadsSubkey = [](
size_t , LoadInst *LI) {
12074 SmallMapVector<std::tuple<size_t, size_t, Type *>, SmallSetVector<Value *, 4>,
12077 for (
const std::unique_ptr<TreeEntry> &TE : VectorizableTree) {
12079 if (!
TE->isGather() || !
TE->UserTreeIndex ||
12080 TE->UserTreeIndex.UserTE->isGather() || !
isSplat(
TE->Scalars))
12088 (UserIgnoreList && UserIgnoreList->contains(
I)))
12094 auto [
Key, SubKey] =
12096 Groups[std::make_tuple(
Key, SubKey,
I->getType())].insert(
I);
12101 SmallMapVector<std::pair<size_t, Type *>, SmallSetVector<Value *, 4>, 4>
12104 if (Group.size() >= 2)
12106 FallbackGroups[std::make_pair(std::get<0>(
Key), Group.front()->getType())]
12109 InstructionsCompatibilityAnalysis
Analysis(*DT, *DL, *TTI, *TLI);
12110 auto BuildSubtree = [&](
const auto &GroupMap) {
12111 for (
const auto &[
_, Group] : GroupMap) {
12112 if (Group.size() < 2)
12115 if (!
Analysis.buildInstructionsState(Group.getArrayRef(), *
this))
12117 unsigned PrevSize = VectorizableTree.size();
12118 buildTreeRec(Group.getArrayRef(), 0,
EdgeInfo());
12119 if (PrevSize == VectorizableTree.size())
12121 TreeEntry *NewRoot = VectorizableTree[PrevSize].get();
12122 if (NewRoot->isGather()) {
12125 for (
Value *V : NewRoot->Scalars) {
12126 auto It = ValueToGatherNodes.find(V);
12127 if (It != ValueToGatherNodes.end())
12128 It->second.remove(NewRoot);
12130 LoadEntriesToVectorize.remove(PrevSize);
12131 VectorizableTree.pop_back();
12134 SplatGatheredScalarsRoots.push_back(NewRoot);
12138 BuildSubtree(FallbackGroups);
12141BoUpSLP::ScalarsVectorizationLegality
12143 const EdgeInfo &UserTreeIdx)
const {
12146 InstructionsCompatibilityAnalysis
Analysis(*DT, *DL, *TTI, *TLI);
12147 InstructionsState S =
Analysis.buildInstructionsState(
12150 bool AreScatterAllGEPSameBlock =
false;
12152 SmallVector<unsigned> SortedIndices;
12154 bool IsScatterVectorizeUserTE =
12155 UserTreeIdx.UserTE &&
12156 UserTreeIdx.UserTE->State == TreeEntry::ScatterVectorize;
12157 AreScatterAllGEPSameBlock =
12171 *SE, SortedIndices));
12172 if (!AreScatterAllGEPSameBlock) {
12173 LLVM_DEBUG(
dbgs() <<
"SLP: Try split and if failed, gathering due to "
12174 "C,S,B,O, small shuffle. \n";
12178 return ScalarsVectorizationLegality(S,
false,
12184 assert(It != VL.
end() &&
"Expected at least one GEP.");
12187 assert(S &&
"Must be valid.");
12192 if (S.
getOpcode() == Instruction::PHI) {
12193 unsigned NumIncomingValues =
12195 if (
static_cast<uint64_t>(VL.
size()) * NumIncomingValues >
12197 LLVM_DEBUG(
dbgs() <<
"SLP: Gathering due to wide PHI operand fan-out ("
12198 << VL.
size() <<
" lanes x " << NumIncomingValues
12199 <<
" incoming values).\n");
12200 return ScalarsVectorizationLegality(S,
false);
12208 return ScalarsVectorizationLegality(S,
false,
12217 !DT->isReachableFromEntry(BB)) {
12223 return ScalarsVectorizationLegality(S,
false);
12232 return ScalarsVectorizationLegality(S,
false,
12237 if (S.
getOpcode() == Instruction::ExtractElement &&
12240 LLVM_DEBUG(
dbgs() <<
"SLP: Gathering due to scalable vector type.\n");
12241 return ScalarsVectorizationLegality(S,
false);
12255 LLVM_DEBUG(
dbgs() <<
"SLP: Gathering due to max recursion depth.\n");
12256 return ScalarsVectorizationLegality(S,
false);
12262 const bool IsPHIWithLoop =
12265 for (TreeEntry *
E : getTreeEntries(S.
getMainOp())) {
12266 if (
E->isSame(VL)) {
12269 return ScalarsVectorizationLegality(S,
false);
12277 return ScalarsVectorizationLegality(S,
false);
12281 bool AreAllSameBlock = !AreScatterAllGEPSameBlock;
12282 bool AreAllSameInsts = AreAllSameBlock || AreScatterAllGEPSameBlock;
12283 if (!AreAllSameInsts ||
isSplat(VL) ||
12287 LLVM_DEBUG(
dbgs() <<
"SLP: Gathering due to C,S,B,O conditions. \n";
12291 return ScalarsVectorizationLegality(S,
false);
12295 if (!EphValues.empty()) {
12296 for (
Value *V : VL) {
12297 if (EphValues.count(V)) {
12299 <<
") is ephemeral.\n");
12301 return ScalarsVectorizationLegality(S,
false,
12314 auto GetNumVectorizedExtracted = [&]() {
12320 all_of(
I->operands(), [&](
const Use &U) {
12321 return isa<ExtractElementInst>(U.get());
12326 else if (!
I->hasOneUser() && !areAllUsersVectorized(
I, UserIgnoreList))
12329 return std::make_pair(Vectorized, Extracted);
12331 auto [Vectorized, Extracted] = GetNumVectorizedExtracted();
12332 bool PreferScalarize = !Vectorized.
isAllOnes() && VL.size() == 2;
12333 if (!Vectorized.
isAllOnes() && !PreferScalarize) {
12336 Type *ScalarTy = VL.front()->getType();
12344 *TTI,
SLPReVec, ScalarTy, VecTy, Vectorized,
12345 true,
false, CostKind,
false);
12346 PreferScalarize = VectorizeCostEstimate > ScalarizeCostEstimate;
12348 if (PreferScalarize) {
12349 LLVM_DEBUG(
dbgs() <<
"SLP: The instructions are in tree and alternate "
12350 "node is not profitable.\n");
12351 return ScalarsVectorizationLegality(S,
false);
12356 if (UserIgnoreList && !UserIgnoreList->empty()) {
12357 for (
Value *V : VL) {
12358 if (UserIgnoreList->contains(V)) {
12359 LLVM_DEBUG(
dbgs() <<
"SLP: Gathering due to gathered scalar.\n");
12360 return ScalarsVectorizationLegality(S,
false);
12365 return ScalarsVectorizationLegality(S,
true);
12384 "Expected the initial 2 operand columns.");
12386 auto IsSub = [](
unsigned Opcode) {
12387 return Opcode == Instruction::Sub || Opcode == Instruction::FSub;
12390 struct SignedColumn {
12397 InstructionsCompatibilityAnalysis
Analysis(DT,
DL,
TTI, TLI);
12404 auto IsRealLane = [&](
Value *V) {
12406 return I &&
I->hasOneUse() &&
12430 for (
unsigned Idx = 0; Idx != Columns.
size();) {
12438 Analysis.buildOperands(ColS, Column);
12439 assert(SubOperands.
size() == 2 &&
"Expected 2 operand columns.");
12443 for (
Value *V : Column)
12447 const bool Negated = Columns[Idx].Negated;
12448 Columns[Idx].Col = std::move(SubOperands.
front());
12450 std::next(Columns.
begin(), Idx + 1),
12451 {std::move(SubOperands.back()), IsSub(ColS.getOpcode()) != Negated});
12455 for (
auto &[Col, Negated] : Columns) {
12456 Operands.push_back(std::move(Col));
12472 function_ref<
bool(
unsigned Lane,
unsigned Col)> IsNegated,
12474 const unsigned NumCols =
Operands.size();
12475 const unsigned NumLanes =
Operands.front().size();
12476 auto LoadsSubkey = [](
size_t ,
LoadInst *LI) {
12479 auto GetKey = [&](
Value *V) {
12482 const std::pair<size_t, size_t> NoSecondaryKey{0, 0};
12485 auto GetSecondaryKey = [&](
Value *V) -> std::pair<size_t, size_t> {
12488 return NoSecondaryKey;
12489 return GetKey(
I->getOperand(0));
12495 return GetSecondaryKey(Col[0]);
12505 using Key = std::pair<std::pair<size_t, size_t>,
unsigned>;
12506 auto Sign = [&](
unsigned Col) {
return IsNegated(Lane, Col) ? 1U : 0U; };
12509 Buckets[{GetKey(
Operands[Col][Lane]), Sign(Col)}].push_back(Col);
12514 const auto SlotKey = std::make_pair(Lane0Keys[Slot], Sign(Slot));
12515 auto BucketIt = Buckets.
find(SlotKey);
12516 if (BucketIt == Buckets.
end())
12518 unsigned &Cursor = NextInBucket[SlotKey];
12519 if (Cursor >= BucketIt->second.size())
12523 unsigned PickPos = Cursor;
12524 if (Lane0SecondaryKeys[Slot] != NoSecondaryKey)
12525 for (
unsigned P = Cursor,
E = BucketIt->second.size();
P !=
E; ++
P)
12526 if (GetSecondaryKey(
Operands[BucketIt->second[
P]][Lane]) ==
12527 Lane0SecondaryKeys[Slot]) {
12531 std::swap(BucketIt->second[Cursor], BucketIt->second[PickPos]);
12532 unsigned SrcCol = BucketIt->second[Cursor++];
12533 SlotSrcCol[Slot] = SrcCol;
12534 ColClaimed[SrcCol] =
true;
12539 if (SlotSrcCol[Slot] != NumCols)
12542 if (!ColClaimed[Col] && IsNegated(Lane, Col) == IsNegated(Lane, Slot)) {
12543 SlotSrcCol[Slot] = Col;
12544 ColClaimed[Col] =
true;
12558static std::tuple<unsigned, unsigned, unsigned, int>
12561 unsigned NumConsecutiveLoadCols = 0;
12562 unsigned NumOtherVecLoadCols = 0;
12563 unsigned NumBroadcastOrConstCols = 0;
12564 int NumUniqueValues = 0;
12568 ++NumBroadcastOrConstCols;
12573 for (
Value *V : Col)
12576 NumUniqueValues += UniqueValues.
size();
12577 if (UniqueValues.
size() <= 1) {
12578 ++NumBroadcastOrConstCols;
12586 R.canVectorizeLoads(Col, Col.front(), Order, PointerOps, SPtrInfo);
12588 ++NumConsecutiveLoadCols;
12590 ++NumOtherVecLoadCols;
12594 return std::make_tuple(NumConsecutiveLoadCols, NumOtherVecLoadCols,
12595 NumBroadcastOrConstCols, -NumUniqueValues);
12600 unsigned InterleaveFactor) {
12603 SmallVector<int> ReuseShuffleIndices;
12607 auto TrySplitNode = [&](
const InstructionsState &LocalState) {
12613 auto Invalid = ScheduleBundle::invalid();
12614 auto *
TE = newTreeEntry(VL, TreeEntry::SplitVectorize,
Invalid, LocalState,
12615 UserTreeIdx, {}, ReorderIndices);
12620 getSameValuesTreeEntry(S.
getMainOp(),
Op,
true))) {
12622 TE->CombinedEntriesWithIndices.emplace_back(VectorizableTree.size(),
12623 Idx == 0 ? 0 : Op1.
size());
12624 (void)newTreeEntry(
Op, TreeEntry::NeedToGather,
Invalid, S, {
TE, Idx});
12626 TE->CombinedEntriesWithIndices.emplace_back(VectorizableTree.size(),
12627 Idx == 0 ? 0 : Op1.
size());
12637 bool AreConsts =
false;
12638 for (
Value *V : VL) {
12650 if (AreOnlyConstsWithPHIs(VL)) {
12651 LLVM_DEBUG(
dbgs() <<
"SLP: Gathering due to all constants and PHIs.\n");
12656 ScalarsVectorizationLegality Legality =
12657 getScalarsVectorizationLegality(VL,
Depth, UserTreeIdx);
12658 InstructionsState S = Legality.getInstructionsState();
12659 if (!Legality.isLegal()) {
12660 if (Legality.trySplitVectorize()) {
12663 if (MainOp && AltOp && TrySplitNode(InstructionsState(MainOp, AltOp)))
12666 if (Legality.tryToFindDuplicates())
12668 UserTreeIdx, *
this);
12670 newGatherTreeEntry(VL, S, UserTreeIdx, ReuseShuffleIndices);
12688 return CI && !SameOrSwapped(CI, MainI->
getPredicate());
12690 ICmpInst *AltI = AltIt == VL.end() ? nullptr :
cast<ICmpInst>(*AltIt);
12695 return !CI || SameOrSwapped(CI, MainI->
getPredicate()) ||
12696 SameOrSwapped(CI, AltI->getPredicate());
12698 TrySplitNode(InstructionsState(MainI, AltI)))
12705 newGatherTreeEntry(VL, S, UserTreeIdx, ReuseShuffleIndices);
12710 bool IsScatterVectorizeUserTE =
12711 UserTreeIdx.UserTE &&
12712 UserTreeIdx.UserTE->State == TreeEntry::ScatterVectorize;
12716 SmallVector<int> ExpandShuffleMask;
12717 TreeEntry::EntryState State = getScalarsVectorizationState(
12718 S, VL, IsScatterVectorizeUserTE, CurrentOrder, PointerOps, SPtrInfo,
12719 ExpandShuffleMask);
12720 if (State == TreeEntry::NeedToGather) {
12721 newGatherTreeEntry(VL, S, UserTreeIdx, ReuseShuffleIndices);
12728 if (VectorizableTree.empty()) {
12729 assert(CurrentLoopNest.empty() &&
"Expected empty loop nest");
12732 if (
const Loop *L = LI->getLoopFor(Parent)) {
12735 CurrentLoopNest.assign(getLoopNest(L));
12737 }
else if (!UserTreeIdx ||
12738 UserTreeIdx.UserTE->State == TreeEntry::SplitVectorize ||
12739 UserTreeIdx.UserTE->isGather() ||
12740 UserTreeIdx.UserTE->getMainOp()->getParent() !=
12743 if (
const Loop *L = LI->getLoopFor(Parent)) {
12756 SmallVector<const Loop *> NewLoopNest(getLoopNest(L));
12757 unsigned CommonLen = 0;
12758 for (
const auto [L1, L2] :
zip(CurrentLoopNest, NewLoopNest)) {
12763 auto ValidateMergedBTCs = [&](
unsigned StartDepth) ->
bool {
12764 unsigned EndDepth =
12765 std::min<unsigned>(NewLoopNest.size(), MergedLoopBTCs.size());
12766 for (
unsigned D = StartDepth;
D < EndDepth; ++
D) {
12767 const SCEV *Constraint = MergedLoopBTCs[
D];
12770 const SCEV *NewBTC = SE->getBackedgeTakenCount(NewLoopNest[
D]);
12776 auto BailOutToGather = [&]() {
12778 <<
"SLP: Sibling loops have different trip counts.\n");
12779 newGatherTreeEntry(VL, S, UserTreeIdx, ReuseShuffleIndices);
12781 if (CurrentLoopNest.empty()) {
12782 if (!ValidateMergedBTCs(0)) {
12786 CurrentLoopNest.assign(NewLoopNest);
12787 }
else if (CommonLen < CurrentLoopNest.size() &&
12788 CommonLen < NewLoopNest.size()) {
12797 const Loop *SibA = CurrentLoopNest[CommonLen];
12798 const Loop *SibB = NewLoopNest[CommonLen];
12799 const SCEV *BecA = SE->getBackedgeTakenCount(SibA);
12800 const SCEV *BecB = SE->getBackedgeTakenCount(SibB);
12805 if (!ValidateMergedBTCs(CommonLen + 1)) {
12809 if (MergedLoopBTCs.size() <= CommonLen)
12810 MergedLoopBTCs.resize(CommonLen + 1,
nullptr);
12811 MergedLoopBTCs[CommonLen] = BecA;
12812 CurrentLoopNest.truncate(CommonLen);
12813 }
else if (NewLoopNest.size() > CurrentLoopNest.size()) {
12814 if (!ValidateMergedBTCs(CurrentLoopNest.size())) {
12818 CurrentLoopNest.append(
12819 std::next(NewLoopNest.begin(), CurrentLoopNest.size()),
12820 NewLoopNest.end());
12829 auto &BSRef = BlocksSchedules[BB];
12831 BSRef = std::make_unique<BlockScheduling>(BB);
12833 BlockScheduling &BS = *BSRef;
12836 std::optional<ScheduleBundle *> BundlePtr =
12837 BS.tryScheduleBundle(UniqueValues.getArrayRef(),
this, S, UserTreeIdx);
12838#ifdef EXPENSIVE_CHECKS
12842 if (!BundlePtr || (*BundlePtr && !*BundlePtr.value())) {
12843 LLVM_DEBUG(
dbgs() <<
"SLP: We are not able to schedule this bundle!\n");
12849 ReuseShuffleIndices.
empty()) {
12851 if (AltS && AltS.
isAltShuffle() && TrySplitNode(AltS))
12854 newGatherTreeEntry(VL, S, UserTreeIdx, ReuseShuffleIndices);
12855 NonScheduledFirst.insert(VL.front());
12856 if (S.
getOpcode() == Instruction::Load &&
12857 BS.ScheduleRegionSize < BS.ScheduleRegionSizeLimit)
12861 InstructionsCompatibilityAnalysis
Analysis(*DT, *DL, *TTI, *TLI);
12875 SmallBitVector NegatedColumns;
12877 SmallBitVector SubLanes;
12883 std::tuple<unsigned, unsigned, unsigned, int> ReassocPeeledQuality;
12895 ReassocScalars, SubLanes);
12896 !Flattened.empty()) {
12898 for (
auto &Col : Flattened)
12899 Operands.emplace_back(std::move(Col));
12903 NegatedColumns, ReassocScalars);
12907 if (!ReassocScalars.
empty()) {
12908 auto IsNegated = [&](
unsigned Lane,
unsigned Col) {
12910 : NegatedColumns.
test(Col);
12912 ReassocAlignedOperands =
12923 auto DropUniqueCount = [](
const auto &Quality) {
12924 return std::make_tuple(std::get<0>(Quality), std::get<1>(Quality),
12925 std::get<2>(Quality));
12929 DropUniqueCount(ReassocPeeledQuality)) {
12930 Operands = std::move(NaturalTwoColumns);
12931 ReassocScalars.
clear();
12937 auto RegisterReassocScalars = [&](TreeEntry *
TE) {
12938 for (
Value *V : ReassocScalars) {
12939 TE->addReassocScalar(V);
12940 SmallVectorImpl<const TreeEntry *> &Owners =
12941 ReassocScalarToTreeEntries.try_emplace(V).first->second;
12949 auto HasDupColumnValues = [&]() {
12950 SmallPtrSet<const Value *, 16> ColumnValues;
12957 ScheduleBundle
Empty;
12958 ScheduleBundle &Bundle = BundlePtr.value() ? *BundlePtr.value() :
Empty;
12959 LLVM_DEBUG(
dbgs() <<
"SLP: We are able to schedule this bundle.\n");
12961 unsigned ShuffleOrOp =
12963 auto CreateOperandNodes = [&](TreeEntry *
TE,
const auto &
Operands) {
12965 SmallVector<unsigned> PHIOps;
12976 for (
unsigned I : PHIOps)
12979 switch (ShuffleOrOp) {
12980 case Instruction::PHI: {
12982 newTreeEntry(VL, Bundle, S, UserTreeIdx, ReuseShuffleIndices);
12990 case Instruction::ExtractValue:
12991 case Instruction::ExtractElement: {
12992 if (CurrentOrder.empty()) {
12993 LLVM_DEBUG(
dbgs() <<
"SLP: Reusing or shuffling extract sequence.\n");
12996 dbgs() <<
"SLP: Reusing or shuffling of reordered extract sequence "
12998 for (
unsigned Idx : CurrentOrder)
12999 dbgs() <<
" " << Idx;
13006 TreeEntry *
TE = newTreeEntry(VL, Bundle , S, UserTreeIdx,
13007 ReuseShuffleIndices, CurrentOrder);
13009 "(ExtractValueInst/ExtractElementInst).\n";
13014 if (ShuffleOrOp == Instruction::ExtractValue) {
13015 SmallVector<unsigned> Indices;
13018 TE->StructEVIndices = std::move(Indices);
13024 case Instruction::InsertValue:
13025 case Instruction::InsertElement: {
13026 assert(ReuseShuffleIndices.
empty() &&
"All inserts should be unique");
13028 auto OrdCompare = [](
const std::pair<int, int> &
P1,
13029 const std::pair<int, int> &
P2) {
13030 return P1.first >
P2.first;
13033 decltype(OrdCompare)>
13034 Indices(OrdCompare);
13035 for (
int I = 0,
E = VL.size();
I <
E; ++
I) {
13037 Indices.emplace(Idx,
I);
13039 OrdersType CurrentOrder(VL.size(), VL.size());
13040 bool IsIdentity =
true;
13041 for (
int I = 0,
E = VL.size();
I <
E; ++
I) {
13042 CurrentOrder[Indices.top().second] =
I;
13043 IsIdentity &= Indices.top().second ==
I;
13047 CurrentOrder.clear();
13048 TreeEntry *
TE = newTreeEntry(VL, Bundle , S, UserTreeIdx,
13050 LLVM_DEBUG(
dbgs() <<
"SLP: added a new TreeEntry (InsertElementInst).\n";
13054 buildTreeRec(
TE->getOperand(1),
Depth + 1, {TE, 1});
13057 case Instruction::Load: {
13064 TreeEntry *
TE =
nullptr;
13067 case TreeEntry::Vectorize:
13068 TE = newTreeEntry(VL, Bundle , S, UserTreeIdx,
13069 ReuseShuffleIndices, CurrentOrder, InterleaveFactor);
13070 if (CurrentOrder.empty())
13071 LLVM_DEBUG(
dbgs() <<
"SLP: added a new TreeEntry (LoadInst).\n";
13075 <<
"SLP: added a new TreeEntry (jumbled LoadInst).\n";
13078 case TreeEntry::CompressVectorize:
13080 TE = newTreeEntry(VL, TreeEntry::CompressVectorize, Bundle, S,
13081 UserTreeIdx, ReuseShuffleIndices, CurrentOrder);
13084 <<
"SLP: added a new TreeEntry (masked LoadInst + compress).\n";
13087 case TreeEntry::StridedVectorize:
13089 TE = newTreeEntry(VL, TreeEntry::StridedVectorize, Bundle, S,
13090 UserTreeIdx, ReuseShuffleIndices, CurrentOrder);
13091 TreeEntryToStridedPtrInfoMap[
TE] = SPtrInfo;
13092 LLVM_DEBUG(
dbgs() <<
"SLP: added a new TreeEntry (strided LoadInst).\n";
13095 case TreeEntry::ScatterVectorize:
13097 TE = newTreeEntry(VL, TreeEntry::ScatterVectorize, Bundle, S,
13098 UserTreeIdx, ReuseShuffleIndices);
13101 <<
"SLP: added a new TreeEntry (non-consecutive LoadInst).\n";
13104 case TreeEntry::BlendedLoadVectorize: {
13108 TE = newTreeEntry(VL, TreeEntry::BlendedLoadVectorize, Bundle, S,
13109 UserTreeIdx, ReuseShuffleIndices);
13110 LLVM_DEBUG(
dbgs() <<
"SLP: added a new TreeEntry (blended LoadInst).\n";
13112 Value *TrueBase =
nullptr;
13113 Value *FalseBase =
nullptr;
13116 VL0->
getType(), PointerOps, *DL, TrueBase, FalseBase, Conditions);
13117 assert(Found &&
"Expected a valid blended-load pattern.");
13120 buildTreeRec(
TE->getOperand(0),
Depth + 1, {TE, 0});
13123 case TreeEntry::ExpandVectorize:
13124 case TreeEntry::CombinedVectorize:
13125 case TreeEntry::SplitVectorize:
13126 case TreeEntry::NeedToGather:
13129 if (!CurrentOrder.empty() && State != TreeEntry::ScatterVectorize) {
13130 assert(
Operands.size() == 1 &&
"Expected a single operand only");
13131 SmallVector<int>
Mask;
13136 if (State == TreeEntry::ScatterVectorize)
13137 buildTreeRec(PointerOps,
Depth + 1, {
TE, 0});
13140 case Instruction::ZExt:
13141 case Instruction::SExt:
13142 case Instruction::FPToUI:
13143 case Instruction::FPToSI:
13144 case Instruction::FPExt:
13145 case Instruction::PtrToInt:
13146 case Instruction::PtrToAddr:
13147 case Instruction::IntToPtr:
13148 case Instruction::SIToFP:
13149 case Instruction::UIToFP:
13150 case Instruction::Trunc:
13151 case Instruction::FPTrunc:
13152 case Instruction::BitCast: {
13153 auto [PrevMaxBW, PrevMinBW] = CastMaxMinBWSizes.value_or(
13154 std::make_pair(std::numeric_limits<unsigned>::min(),
13155 std::numeric_limits<unsigned>::max()));
13156 if (ShuffleOrOp == Instruction::ZExt ||
13157 ShuffleOrOp == Instruction::SExt) {
13158 CastMaxMinBWSizes = std::make_pair(
13159 std::max<unsigned>(DL->getTypeSizeInBits(VL0->
getType()),
13161 std::min<unsigned>(
13164 }
else if (ShuffleOrOp == Instruction::Trunc) {
13165 CastMaxMinBWSizes = std::make_pair(
13166 std::max<unsigned>(
13169 std::min<unsigned>(DL->getTypeSizeInBits(VL0->
getType()),
13172 TreeEntry *
TE = newTreeEntry(VL, Bundle , S, UserTreeIdx,
13173 ReuseShuffleIndices);
13174 LLVM_DEBUG(
dbgs() <<
"SLP: added a new TreeEntry (CastInst).\n";
13179 buildTreeRec(
TE->getOperand(
I),
Depth, {TE, I});
13180 if (ShuffleOrOp == Instruction::Trunc) {
13181 ExtraBitWidthNodes.insert(getOperandEntry(TE, 0)->Idx);
13182 }
else if (ShuffleOrOp == Instruction::SIToFP ||
13183 ShuffleOrOp == Instruction::UIToFP) {
13184 unsigned NumSignBits =
13187 APInt
Mask = DB->getDemandedBits(OpI);
13188 NumSignBits = std::max(NumSignBits,
Mask.countl_zero());
13190 if (NumSignBits * 2 >=
13192 ExtraBitWidthNodes.insert(getOperandEntry(TE, 0)->Idx);
13196 case Instruction::ICmp:
13197 case Instruction::FCmp: {
13200 TreeEntry *
TE = newTreeEntry(VL, Bundle , S, UserTreeIdx,
13201 ReuseShuffleIndices);
13210 "Commutative Predicate mismatch");
13222 if (
Cmp->getPredicate() != P0 &&
13230 if (ShuffleOrOp == Instruction::ICmp) {
13231 unsigned NumSignBits0 =
13233 if (NumSignBits0 * 2 >=
13235 ExtraBitWidthNodes.insert(getOperandEntry(TE, 0)->Idx);
13236 unsigned NumSignBits1 =
13238 if (NumSignBits1 * 2 >=
13240 ExtraBitWidthNodes.insert(getOperandEntry(TE, 1)->Idx);
13244 case Instruction::Select:
13245 case Instruction::FNeg:
13246 case Instruction::Add:
13247 case Instruction::FAdd:
13248 case Instruction::Sub:
13249 case Instruction::FSub:
13250 case Instruction::Mul:
13251 case Instruction::FMul:
13252 case Instruction::UDiv:
13253 case Instruction::SDiv:
13254 case Instruction::FDiv:
13255 case Instruction::URem:
13256 case Instruction::SRem:
13257 case Instruction::FRem:
13258 case Instruction::Shl:
13259 case Instruction::LShr:
13260 case Instruction::AShr:
13261 case Instruction::And:
13262 case Instruction::Or:
13263 case Instruction::Xor:
13264 case Instruction::Freeze: {
13265 TreeEntry *
TE = newTreeEntry(VL, Bundle , S, UserTreeIdx,
13266 ReuseShuffleIndices);
13268 dbgs() <<
"SLP: added a new TreeEntry "
13269 "(SelectInst/UnaryOperator/BinaryOperator/FreezeInst).\n";
13272 if (!ReassocScalars.empty()) {
13283 SmallVector<unsigned> GroupIds[2];
13286 for (ArrayRef<unsigned> Group : GroupIds) {
13287 if (Group.size() <= 1)
13290 Group, [&](
unsigned I) {
return ReassocAlignedOperands[
I]; });
13294 Reordered[Group[Pos]] =
Ops.getVL(Pos);
13297 ReassocPeeledQuality)
13301 "structure, keeping the natural operand "
13304 Operands = std::move(ReassocAlignedOperands);
13306 if (HasDupColumnValues()) {
13307 Operands = std::move(NaturalTwoColumns);
13308 ReassocScalars.clear();
13311 if (!ReassocScalars.empty())
13312 RegisterReassocScalars(TE);
13320 if (!ReassocScalars.empty() && NegatedColumns.
any())
13321 TE->setReassocNegatedOps(NegatedColumns);
13323 buildTreeRec(
TE->getOperand(
I),
Depth + 1, {TE, I});
13326 case Instruction::GetElementPtr: {
13327 TreeEntry *
TE = newTreeEntry(VL, Bundle , S, UserTreeIdx,
13328 ReuseShuffleIndices);
13329 LLVM_DEBUG(
dbgs() <<
"SLP: added a new TreeEntry (GetElementPtrInst).\n";
13337 case Instruction::Store: {
13338 assert(CurrentOrder.empty() &&
13339 "Expected ordered store during tree building");
13340 if (State == TreeEntry::StridedVectorize) {
13342 newTreeEntry(VL, TreeEntry::StridedVectorize, Bundle, S,
13343 UserTreeIdx, ReuseShuffleIndices, CurrentOrder);
13344 TreeEntryToStridedPtrInfoMap[
TE] = SPtrInfo;
13346 dbgs() <<
"SLP: added a new TreeEntry (strided StoreInst).\n";
13349 buildTreeRec(
TE->getOperand(0),
Depth + 1, {TE, 0});
13352 if (State == TreeEntry::ExpandVectorize) {
13354 "Expected no reuse shuffle for an expanded masked store.");
13356 newTreeEntry(VL, TreeEntry::ExpandVectorize, Bundle, S, UserTreeIdx,
13357 ExpandShuffleMask, CurrentOrder);
13358 TreeEntryToStridedPtrInfoMap[
TE] = SPtrInfo;
13361 <<
"SLP: added a new TreeEntry (expanded masked StoreInst).\n";
13364 buildTreeRec(
TE->getOperand(0),
Depth + 1, {TE, 0});
13367 TreeEntry *
TE = newTreeEntry(VL, Bundle , S, UserTreeIdx,
13368 ReuseShuffleIndices, CurrentOrder);
13369 LLVM_DEBUG(
dbgs() <<
"SLP: added a new TreeEntry (StoreInst).\n";
13372 buildTreeRec(
TE->getOperand(0),
Depth + 1, {TE, 0});
13375 case Instruction::Call: {
13381 TreeEntry *
TE = newTreeEntry(VL, Bundle , S, UserTreeIdx,
13382 ReuseShuffleIndices);
13383 LLVM_DEBUG(
dbgs() <<
"SLP: added a new TreeEntry (CallInst).\n";
13397 buildTreeRec(
TE->getOperand(
I),
Depth + 1, {TE, I});
13401 case Instruction::ShuffleVector: {
13402 TreeEntry *
TE = newTreeEntry(VL, Bundle , S, UserTreeIdx,
13403 ReuseShuffleIndices);
13405 LLVM_DEBUG(
dbgs() <<
"SLP: added a new TreeEntry (isAltShuffle).\n";
13410 dbgs() <<
"SLP: added a new TreeEntry (ShuffleVectorInst).\n";
13424 "Expected different main/alternate predicates.");
13446 if (!ReassocScalars.empty()) {
13449 Operands = std::move(ReassocAlignedOperands);
13450 if (HasDupColumnValues()) {
13451 Operands = std::move(NaturalTwoColumns);
13452 ReassocScalars.clear();
13461 if (!ReassocScalars.empty())
13462 RegisterReassocScalars(TE);
13465 buildTreeRec(
TE->getOperand(
I),
Depth + 1, {TE, I});
13483 for (
const auto *Ty : ST->elements())
13484 if (Ty != *ST->element_begin())
13486 N *= ST->getNumElements();
13487 EltTy = *ST->element_begin();
13489 N *= AT->getNumElements();
13490 EltTy = AT->getElementType();
13493 N *= VT->getNumElements();
13494 EltTy = VT->getElementType();
13500 size_t VTSize = DL->getTypeStoreSizeInBits(
getWidenedType(EltTy,
N));
13501 if (VTSize < MinVecRegSize || VTSize > MaxVecRegSize ||
13502 VTSize != DL->getTypeStoreSizeInBits(T))
13508 if (E->getOpcode() != Instruction::InsertValue ||
13509 E->State != TreeEntry::Vectorize)
13512 bool HasStore =
false;
13513 for (
Value *V : E->Scalars) {
13518 bool HasExternalUser =
false;
13519 for (
User *U :
IV->users()) {
13524 HasExternalUser =
true;
13529 if (!
SI || !
SI->isSimple())
13533 if (HasExternalUser && !
IV->hasOneUse())
13540 Value *VL0 = E->getMainOp();
13541 if (E->getOpcode() == Instruction::InsertElement)
13543 assert(E->getOpcode() == Instruction::InsertValue &&
13544 "Expected InsertElement or InsertValue node.");
13545 unsigned MaxIdx = E->Scalars.size() - 1;
13546 for (
Value *V : E->Scalars) {
13550 MaxIdx = std::max(MaxIdx,
I->getIndices().front());
13558 bool ResizeAllowed)
const {
13560 assert(It != VL.
end() &&
"Expected at least one extract instruction.");
13564 Value *Vec = E0->getOperand(0);
13566 CurrentOrder.
clear();
13570 if (E0->getOpcode() == Instruction::ExtractValue) {
13582 unsigned E = VL.
size();
13583 if (!ResizeAllowed && NElts !=
E)
13586 unsigned MinIdx = NElts, MaxIdx = 0;
13593 if (Inst->getOperand(0) != Vec)
13601 const unsigned ExtIdx = *Idx;
13602 if (ExtIdx >= NElts)
13604 Indices[
I] = ExtIdx;
13605 if (MinIdx > ExtIdx)
13607 if (MaxIdx < ExtIdx)
13610 if (MaxIdx - MinIdx + 1 >
E)
13612 if (MaxIdx + 1 <=
E)
13616 bool ShouldKeepOrder =
true;
13623 for (
unsigned I = 0;
I <
E; ++
I) {
13626 const unsigned ExtIdx = Indices[
I] - MinIdx;
13627 if (CurrentOrder[ExtIdx] !=
E) {
13628 CurrentOrder.
clear();
13631 ShouldKeepOrder &= ExtIdx ==
I;
13632 CurrentOrder[ExtIdx] =
I;
13634 if (ShouldKeepOrder)
13635 CurrentOrder.
clear();
13637 return ShouldKeepOrder;
13640bool BoUpSLP::areAllUsersVectorized(
13641 Instruction *
I,
const SmallDenseSet<Value *> *VectorizedVals)
const {
13642 return (
I->hasOneUse() && (!VectorizedVals || VectorizedVals->
contains(
I))) ||
13643 all_of(
I->users(), [
this](User *U) {
13644 return isVectorized(U) || isVectorLikeInstWithConstOps(U) ||
13645 (isa<ExtractElementInst>(U) && MustGather.contains(U));
13650 const InstructionsState &S,
13651 DominatorTree &DT,
const DataLayout &DL,
13652 TargetTransformInfo &TTI,
13653 const TargetLibraryInfo &TLI,
13656uint64_t BoUpSLP::getNumScalarInsts(
bool HasTreeLoop) {
13658 for (
const std::unique_ptr<TreeEntry> &Ptr : VectorizableTree) {
13659 const TreeEntry &
TE = *Ptr;
13660 if (DeletedNodes.contains(&TE))
13669 if (
TE.State == TreeEntry::CombinedVectorize)
13671 uint64_t Scale = getEntryEffectiveScale(TE);
13672 if (HasTreeLoop && Scale <= 1)
13674 unsigned Count = 0;
13675 if (
TE.isGather() || TransformedToGatherNodes.contains(&TE)) {
13688 for (
Value *V :
TE.Scalars) {
13690 (
TE.hasCopyableElements() &&
TE.isCopyableElement(V)))
13696 if (
I && (
I->isIntDivRem() ||
I->isFPDivRem()))
13705 Count +=
TE.getReassocScalars().size();
13711 if (
TE.CombinedOp == TreeEntry::NotCombinedOp &&
TE.hasState()) {
13712 unsigned Opcode =
TE.getOpcode();
13713 if (Opcode == Instruction::Select) {
13714 for (
Value *V :
TE.Scalars) {
13715 if (
TE.hasCopyableElements() &&
TE.isCopyableElement(V))
13722 assert(
Count > 0 &&
"Underflow in scalar inst count (minmax)");
13726 }
else if (Opcode == Instruction::FAdd || Opcode == Instruction::FSub) {
13727 for (
Value *V :
TE.Scalars) {
13728 if (
TE.hasCopyableElements() &&
TE.isCopyableElement(V))
13731 if (!
I || (
TE.isAltShuffle() &&
I->getOpcode() != Instruction::FAdd &&
13732 I->getOpcode() != Instruction::FSub))
13737 assert(
Count > 0 &&
"Underflow in scalar inst count (fma)");
13748uint64_t BoUpSLP::getNumVectorInsts(
bool HasTreeLoop) {
13752 SmallDenseMap<Value *, uint64_t, 4> GatherExtractSourceVecs;
13753 for (
const std::unique_ptr<TreeEntry> &Ptr : VectorizableTree) {
13754 const TreeEntry &
TE = *Ptr;
13755 if (DeletedNodes.contains(&TE))
13757 if (
TE.State == TreeEntry::CombinedVectorize)
13759 uint64_t Scale = getEntryEffectiveScale(TE);
13760 if (HasTreeLoop && Scale <= 1)
13762 unsigned Count = 0;
13763 if (
TE.isGather() || TransformedToGatherNodes.contains(&TE)) {
13764 if (
TE.hasState()) {
13765 if (
const TreeEntry *
E =
13766 getSameValuesTreeEntry(
TE.getMainOp(),
TE.Scalars);
13767 E &&
E != &TE &&
E->getVectorFactor() ==
TE.getVectorFactor())
13770 if (
const TreeEntry *
E =
13771 getSameValuesTreeEntry(
TE.getMainOp(), RevScalars);
13772 E &&
E->getVectorFactor() ==
TE.getVectorFactor()) {
13785 GatherExtractSourceVecs.
try_emplace(EE->getVectorOperand(), 0)
13787 VecScale = std::max(VecScale, Scale);
13790 for (
Value *V :
TE.Scalars) {
13801 if (
TE.getOpcode() == Instruction::InsertElement ||
13802 TE.getOpcode() == Instruction::ExtractElement)
13804 if (
TE.getOpcode() == Instruction::InsertValue) {
13809 if (!
TE.ReorderIndices.empty() || !
TE.ReuseShuffleIndices.empty())
13814 if (
TE.State == TreeEntry::SplitVectorize)
13816 else if (
TE.hasReassocScalars())
13818 Count +=
TE.getNumOperands() - 1;
13821 if (!
TE.ReorderIndices.empty() || !
TE.ReuseShuffleIndices.empty())
13825 for (
const auto &VecAndScale : GatherExtractSourceVecs)
13829 SmallPtrSet<Value *, 8> CountedExtracts;
13830 for (
const ExternalUser &EU : ExternalUses) {
13833 if (EU.User && EphValues.count(EU.User))
13839 (EU.E.hasState() && EU.E.getOpcode() == Instruction::InsertElement)))
13841 if (ExternalUsesAsOriginalScalar.contains(EU.Scalar))
13843 if (!CountedExtracts.
insert(EU.Scalar).second)
13850void BoUpSLP::TreeEntry::buildAltOpShuffleMask(
13851 const function_ref<
bool(Instruction *)> IsAltOp, SmallVectorImpl<int> &Mask,
13852 SmallVectorImpl<Value *> *OpScalars,
13853 SmallVectorImpl<Value *> *AltScalars)
const {
13854 unsigned Sz = Scalars.size();
13856 SmallVector<int> OrderMask;
13857 if (!ReorderIndices.empty())
13859 for (
unsigned I = 0;
I < Sz; ++
I) {
13861 if (!ReorderIndices.empty())
13862 Idx = OrderMask[
I];
13866 if (IsAltOp(OpInst)) {
13867 Mask[
I] = Sz + Idx;
13876 if (!ReuseShuffleIndices.
empty()) {
13878 transform(ReuseShuffleIndices, NewMask.
begin(), [&Mask](
int Idx) {
13879 return Idx != PoisonMaskElem ? Mask[Idx] : PoisonMaskElem;
13881 Mask.swap(NewMask);
13906 return CI->getValue().isPowerOf2();
13912 return CI->getValue().isNegatedPowerOf2();
13917 if (IsConstant && IsUniform)
13919 else if (IsConstant)
13921 else if (IsUniform)
13933class BaseShuffleAnalysis {
13935 Type *ScalarTy =
nullptr;
13937 BaseShuffleAnalysis(
Type *ScalarTy) : ScalarTy(ScalarTy) {}
13945 unsigned getVF(
Value *V)
const {
13946 assert(V &&
"V cannot be nullptr");
13948 "V does not have FixedVectorType");
13949 assert(ScalarTy &&
"ScalarTy cannot be nullptr");
13951 unsigned VNumElements =
13953 assert(VNumElements > ScalarTyNumElements &&
13954 "the number of elements of V is not large enough");
13955 assert(VNumElements % ScalarTyNumElements == 0 &&
13956 "the number of elements of V is not a vectorized value");
13957 return VNumElements / ScalarTyNumElements;
13963 static bool isIdentityMask(ArrayRef<int> Mask,
const FixedVectorType *VecTy,
13965 int Limit =
Mask.size();
13977 if (Limit % VF == 0 &&
all_of(
seq<int>(0, Limit / VF), [=](
int Idx) {
13978 ArrayRef<int> Slice =
Mask.slice(Idx * VF, VF);
13991 static void combineMasks(
unsigned LocalVF, SmallVectorImpl<int> &Mask,
13992 ArrayRef<int> ExtMask) {
13993 unsigned VF =
Mask.size();
13995 for (
int I = 0, Sz = ExtMask.
size();
I < Sz; ++
I) {
13998 int MaskedIdx =
Mask[ExtMask[
I] % VF];
14002 Mask.swap(NewMask);
14038 static bool peekThroughShuffles(
Value *&V, SmallVectorImpl<int> &Mask,
14039 bool SinglePermute) {
14041 ShuffleVectorInst *IdentityOp =
nullptr;
14042 SmallVector<int> IdentityMask;
14051 if (isIdentityMask(Mask, SVTy,
false)) {
14052 if (!IdentityOp || !SinglePermute ||
14053 (isIdentityMask(Mask, SVTy,
true) &&
14055 IdentityMask.
size()))) {
14060 IdentityMask.
assign(Mask);
14080 if (SV->isZeroEltSplat()) {
14082 IdentityMask.
assign(Mask);
14084 int LocalVF =
Mask.size();
14087 LocalVF = SVOpTy->getNumElements();
14091 static_cast<unsigned>(
I) >= SV->getShuffleMask().size())
14093 ExtMask[Idx] = SV->getMaskValue(
I);
14103 if (!IsOp1Undef && !IsOp2Undef) {
14105 for (
int &
I : Mask) {
14108 if (SV->getMaskValue(
I % SV->getShuffleMask().size()) ==
14114 SmallVector<int> ShuffleMask(SV->getShuffleMask());
14115 combineMasks(LocalVF, ShuffleMask, Mask);
14116 Mask.swap(ShuffleMask);
14118 Op = SV->getOperand(0);
14120 Op = SV->getOperand(1);
14123 !OpTy || !isIdentityMask(Mask, OpTy, SinglePermute) ||
14128 "Expected masks of same sizes.");
14133 Mask.swap(IdentityMask);
14135 return SinglePermute &&
14138 (Shuffle &&
Mask.size() == Shuffle->getShuffleMask().size() &&
14139 Shuffle->isZeroEltSplat() &&
14143 Shuffle->getShuffleMask()[
P.index()] == 0;
14156 template <
typename T,
typename ShuffleBuilderTy,
typename...
Args>
14157 static T createShuffle(
Value *
V1,
Value *V2, ArrayRef<int> Mask,
14158 ShuffleBuilderTy &Builder,
Type *ScalarTy,
14160 assert(
V1 &&
"Expected at least one vector value.");
14162 SmallVector<int> NewMask(Mask);
14163 if (ScalarTyNumElements != 1) {
14169 Builder.resizeToMatch(
V1, V2);
14170 int VF =
Mask.size();
14172 VF = FTy->getNumElements();
14183 for (
int I = 0,
E =
Mask.size();
I <
E; ++
I) {
14185 CombinedMask1[
I] =
Mask[
I];
14187 CombinedMask2[
I] =
Mask[
I] - VF;
14194 (void)peekThroughShuffles(Op1, CombinedMask1,
false);
14195 (void)peekThroughShuffles(Op2, CombinedMask2,
false);
14201 for (
auto [Idx,
I] :
enumerate(CombinedMask1)) {
14204 ExtMask1[Idx] = SV1->getMaskValue(
I);
14208 ->getNumElements(),
14209 ExtMask1, UseMask::SecondArg);
14210 SmallVector<int> ExtMask2(CombinedMask2.size(),
PoisonMaskElem);
14211 for (
auto [Idx,
I] :
enumerate(CombinedMask2)) {
14214 ExtMask2[Idx] = SV2->getMaskValue(
I);
14218 ->getNumElements(),
14219 ExtMask2, UseMask::SecondArg);
14220 if (SV1->getOperand(0)->getType() ==
14221 SV2->getOperand(0)->getType() &&
14222 SV1->getOperand(0)->getType() != SV1->getType() &&
14225 Op1 = SV1->getOperand(0);
14226 Op2 = SV2->getOperand(0);
14227 SmallVector<int> ShuffleMask1(SV1->getShuffleMask());
14228 int LocalVF = ShuffleMask1.size();
14230 LocalVF = FTy->getNumElements();
14231 combineMasks(LocalVF, ShuffleMask1, CombinedMask1);
14232 CombinedMask1.swap(ShuffleMask1);
14233 SmallVector<int> ShuffleMask2(SV2->getShuffleMask());
14234 LocalVF = ShuffleMask2.size();
14236 LocalVF = FTy->getNumElements();
14237 combineMasks(LocalVF, ShuffleMask2, CombinedMask2);
14238 CombinedMask2.swap(ShuffleMask2);
14241 }
while (PrevOp1 != Op1 || PrevOp2 != Op2);
14242 Builder.resizeToMatch(Op1, Op2);
14244 ->getElementCount()
14245 .getKnownMinValue(),
14247 ->getElementCount()
14248 .getKnownMinValue());
14249 for (
int I = 0,
E =
Mask.size();
I <
E; ++
I) {
14252 "Expected undefined mask element");
14253 CombinedMask1[
I] = CombinedMask2[
I] + (Op1 == Op2 ? 0 : VF);
14262 return Builder.createIdentity(Op1);
14263 return Builder.createShuffleVector(
14268 return Builder.createPoison(
14270 bool IsIdentity = peekThroughShuffles(
V1, NewMask,
true);
14271 assert(
V1 &&
"Expected non-null value after looking through shuffles.");
14274 return Builder.createShuffleVector(
V1, NewMask,
Arguments...);
14275 return Builder.createIdentity(
V1);
14281 ArrayRef<int> Mask) {
14289void BoUpSLP::reorderGatherNode(TreeEntry &TE) {
14290 assert(
TE.isGather() &&
TE.ReorderIndices.empty() &&
14291 "Expected gather node without reordering.");
14293 SmallSet<size_t, 2> LoadKeyUsed;
14297 if (
TE.Scalars.size() == 2 || (
TE.hasState() && !
TE.isAltShuffle()) ||
14302 return VectorizableTree[Idx]->isSame(TE.Scalars);
14306 auto GenerateLoadsSubkey = [&](
size_t Key, LoadInst *LI) {
14311 auto LIt = LoadsMap.
find(std::make_pair(
Key, Ptr));
14312 if (LIt != LoadsMap.
end()) {
14313 for (LoadInst *RLI : LIt->second) {
14315 LI->
getType(), LI->getPointerOperand(), *DL, *SE,
14319 for (LoadInst *RLI : LIt->second) {
14321 LI->getPointerOperand(), *TLI)) {
14326 if (LIt->second.size() > 2) {
14328 hash_value(LIt->second.back()->getPointerOperand());
14334 LoadsMap.
try_emplace(std::make_pair(
Key, Ptr)).first->second.push_back(LI);
14337 MapVector<size_t, MapVector<size_t, SmallVector<Value *>>> SortedValues;
14338 SmallDenseMap<Value *, SmallVector<unsigned>, 8> KeyToIndex;
14339 bool IsOrdered =
true;
14340 unsigned NumInstructions = 0;
14344 size_t Key = 1, Idx = 1;
14352 auto &Container = SortedValues[
Key];
14353 if (IsOrdered && !KeyToIndex.
contains(V) &&
14356 ((Container.contains(Idx) &&
14357 KeyToIndex.
at(Container[Idx].back()).back() !=
I - 1) ||
14358 (!Container.empty() && !Container.contains(Idx) &&
14359 KeyToIndex.
at(Container.back().second.back()).back() !=
I - 1)))
14361 auto &KTI = KeyToIndex[
V];
14363 Container[Idx].push_back(V);
14368 if (!IsOrdered && NumInstructions > 1) {
14370 TE.ReorderIndices.resize(
TE.Scalars.size(),
TE.Scalars.size());
14371 for (
const auto &
D : SortedValues) {
14372 for (
const auto &
P :
D.second) {
14374 for (
Value *V :
P.second) {
14375 ArrayRef<unsigned> Indices = KeyToIndex.
at(V);
14376 for (
auto [K, Idx] :
enumerate(Indices)) {
14377 TE.ReorderIndices[Cnt +
K] = Idx;
14378 TE.Scalars[Cnt +
K] =
V;
14380 Sz += Indices.
size();
14381 Cnt += Indices.
size();
14385 *TTI,
TE.Scalars.front()->getType(), Sz,
SLPReVec);
14389 }
else if (!
P.second.empty() &&
isConstant(
P.second.front())) {
14397 if (!
TE.ReuseShuffleIndices.empty() ||
TE.ReorderIndices.empty())
14401 auto *ScalarTy =
TE.Scalars.front()->getType();
14403 for (
auto [Idx, Sz] : SubVectors) {
14411 int Sz =
TE.Scalars.size();
14412 SmallVector<int> ReorderMask(
TE.ReorderIndices.begin(),
14413 TE.ReorderIndices.end());
14419 ReorderMask[
I] =
I +
TE.ReorderIndices.size();
14423 any_of(ReorderMask, [&](
int I) {
return I >= Sz; })
14426 VecTy, CostKind, ReorderMask);
14432 DemandedElts.clearBit(
I);
14434 ReorderMask[
I] =
I;
14436 ReorderMask[
I] =
I + Sz;
14441 true,
false, CostKind);
14442 if (!DemandedElts.isAllOnes())
14445 if (
Cost >= BVCost) {
14446 SmallVector<int>
Mask(
TE.ReorderIndices.begin(),
TE.ReorderIndices.end());
14448 TE.ReorderIndices.clear();
14462 return V->getType()->getScalarType()->isFloatingPointTy();
14464 "Can only convert to FMA for floating point types");
14471 for (
Value *V : VL) {
14481 FMF &= FPCI->getFastMathFlags();
14485 if (!CheckForContractable(VL, S))
14488 InstructionsCompatibilityAnalysis
Analysis(DT,
DL,
TTI, TLI);
14497 if (!CheckForContractable(
Operands.front(), OpS))
14506 assert(
I->getOpcode() == Instruction::FMul &&
"Expected an fmul");
14509 return TTI.getArithmeticInstrCost(
I->getOpcode(),
I->getType(),
CostKind,
14511 {I->getOperand(0), I->getOperand(1)});
14517 for (
Value *V : VL) {
14524 FMF &= FPCI->getFastMathFlags();
14525 if (IsCopyable || !IsArithmeticState ||
14528 FMulPlusFAddCost +=
TTI.getInstructionCost(
I,
CostKind);
14533 FMulPlusFAddCost +=
TTI.getArithmeticInstrCost(
14534 I->getOpcode(),
I->getType(),
CostKind, Op1Info, Op2Info,
14535 {I->getOperand(0), I->getOperand(1)});
14544 FMACost +=
TTI.getInstructionCost(OpI,
CostKind);
14551 FMF &= FPCI->getFastMathFlags();
14552 FMulPlusFAddCost += GetUnfusedFMulCost(
I);
14560bool BoUpSLP::matchesShlZExt(
const TreeEntry &TE,
OrdersType &Order,
14561 bool &IsBSwap,
bool &ForLoads)
const {
14562 assert(
TE.hasState() &&
TE.getOpcode() == Instruction::Shl &&
14563 "Expected Shl node.");
14566 if (
TE.State != TreeEntry::Vectorize || !
TE.ReorderIndices.empty() ||
14567 !
TE.ReuseShuffleIndices.empty() || MinBWs.contains(&TE) ||
14568 any_of(
TE.Scalars, [](
Value *V) { return !V->hasOneUse(); }))
14570 Type *ScalarTy =
TE.getMainOp()->getType();
14576 const unsigned Sz = DL->getTypeSizeInBits(ScalarTy);
14577 const TreeEntry *LhsTE = getOperandEntry(&TE, 0);
14578 const TreeEntry *RhsTE = getOperandEntry(&TE, 1);
14580 if (!(LhsTE->State == TreeEntry::Vectorize &&
14581 LhsTE->getOpcode() == Instruction::ZExt &&
14582 LhsTE->ReorderIndices.empty() && LhsTE->ReuseShuffleIndices.empty() &&
14583 !MinBWs.contains(LhsTE) &&
14584 all_of(LhsTE->Scalars, [](
Value *V) { return V->hasOneUse(); })))
14587 unsigned Stride = DL->getTypeSizeInBits(SrcScalarTy);
14588 if (!
isPowerOf2_64(Stride) || Stride >= Sz || Sz % Stride != 0 ||
14591 if (!(RhsTE->isGather() && RhsTE->ReorderIndices.empty() &&
14592 RhsTE->ReuseShuffleIndices.empty() && !MinBWs.contains(RhsTE)))
14595 unsigned CurrentValue = 0;
14597 if (
all_of(RhsTE->Scalars,
14599 CurrentValue += Stride;
14600 if (isa<UndefValue>(V))
14602 auto *C = dyn_cast<Constant>(V);
14605 return C->getUniqueInteger() == CurrentValue - Stride;
14607 CurrentValue <= Sz) {
14610 const unsigned VF = RhsTE->getVectorFactor();
14611 Order.assign(VF, VF);
14613 SmallBitVector SeenPositions(VF);
14616 if (VF * Stride > Sz)
14618 for (
const auto [Idx, V] :
enumerate(RhsTE->Scalars)) {
14624 const APInt &Val =
C->getUniqueInteger();
14629 if (Order[Idx] != VF || Pos >= VF)
14631 if (SeenPositions.test(Pos))
14633 SeenPositions.set(Pos);
14640 auto *SrcType = IntegerType::getIntNTy(ScalarTy->
getContext(),
14641 Stride * LhsTE->getVectorFactor());
14643 SmallPtrSet<Value *, 4> CheckedExtracts;
14649 getCastContextHint(*getOperandEntry(LhsTE, 0));
14651 TTI->getArithmeticReductionCost(Instruction::Or, VecTy, FMF, CostKind) +
14652 TTI->getArithmeticInstrCost(Instruction::Shl, VecTy, CostKind,
14653 getOperandInfo(LhsTE->Scalars)) +
14654 TTI->getCastInstrCost(
14655 Instruction::ZExt, VecTy,
14659 Instruction::BitCast, SrcType, SrcVecTy, CastCtx, CostKind);
14660 if (!Order.empty()) {
14662 SmallVector<int>
Mask;
14668 constexpr unsigned ByteSize = 8;
14670 DL->getTypeSizeInBits(SrcScalarTy) == ByteSize) {
14671 IntrinsicCostAttributes CostAttrs(Intrinsic::bswap, SrcType, {SrcType});
14673 TTI->getCastInstrCost(Instruction::BitCast, SrcType, SrcVecTy, CastCtx,
14675 TTI->getIntrinsicInstrCost(CostAttrs, CostKind);
14676 if (BSwapCost <= BitcastCost) {
14677 BitcastCost = BSwapCost;
14681 const TreeEntry *SrcTE = getOperandEntry(LhsTE, 0);
14682 if (SrcTE->State == TreeEntry::Vectorize &&
14683 SrcTE->ReorderIndices.empty() && SrcTE->ReuseShuffleIndices.empty() &&
14684 SrcTE->getOpcode() == Instruction::Load && !SrcTE->isAltShuffle() &&
14685 all_of(SrcTE->Scalars, [](
Value *V) { return V->hasOneUse(); })) {
14687 IntrinsicCostAttributes CostAttrs(Intrinsic::bswap, SrcType, {SrcType});
14689 TTI->getMemoryOpCost(Instruction::Load, SrcType, LI->getAlign(),
14690 LI->getPointerAddressSpace(), CostKind) +
14691 TTI->getIntrinsicInstrCost(CostAttrs, CostKind);
14692 if (BSwapCost <= BitcastCost) {
14694 TTI->getMemoryOpCost(Instruction::Load, SrcVecTy, LI->getAlign(),
14695 LI->getPointerAddressSpace(), CostKind);
14696 BitcastCost = BSwapCost;
14701 }
else if (Order.empty() && DL->getTypeSizeInBits(SrcScalarTy) == ByteSize) {
14703 const TreeEntry *SrcTE = getOperandEntry(LhsTE, 0);
14704 if (SrcTE->State == TreeEntry::Vectorize && SrcTE->ReorderIndices.empty() &&
14705 SrcTE->ReuseShuffleIndices.empty() &&
14706 SrcTE->getOpcode() == Instruction::Load && !SrcTE->isAltShuffle() &&
14707 all_of(SrcTE->Scalars, [](
Value *V) { return V->hasOneUse(); })) {
14710 TTI->getMemoryOpCost(Instruction::Load, SrcType, LI->getAlign(),
14711 LI->getPointerAddressSpace(), CostKind);
14713 TTI->getMemoryOpCost(Instruction::Load, SrcVecTy, LI->getAlign(),
14714 LI->getPointerAddressSpace(), CostKind);
14718 if (SrcType != ScalarTy) {
14719 BitcastCost += TTI->getCastInstrCost(Instruction::ZExt, ScalarTy, SrcType,
14722 return BitcastCost < VecCost;
14725bool BoUpSLP::matchesInversedZExtSelect(
14726 const TreeEntry &SelectTE,
14727 SmallVectorImpl<unsigned> &InversedCmpsIndices)
const {
14728 assert(SelectTE.hasState() && SelectTE.getOpcode() == Instruction::Select &&
14729 "Expected select node.");
14731 for (
auto [Idx, V] :
enumerate(SelectTE.Scalars)) {
14733 if (!Inst || Inst->getOpcode() != Instruction::ZExt)
14739 const auto *CmpTE = getOperandEntry(&SelectTE, 0);
14740 const auto *Op1TE = getOperandEntry(&SelectTE, 1);
14741 const auto *Op2TE = getOperandEntry(&SelectTE, 2);
14745 if (CmpTE->State != TreeEntry::Vectorize || !CmpTE->isAltShuffle() ||
14746 (CmpTE->getOpcode() != Instruction::ICmp &&
14747 CmpTE->getOpcode() != Instruction::FCmp) ||
14748 !CmpTE->ReorderIndices.empty() || !CmpTE->ReuseShuffleIndices.empty() ||
14749 !Op1TE->ReorderIndices.empty() || !Op1TE->ReuseShuffleIndices.empty() ||
14750 !Op2TE->ReorderIndices.empty() || !Op2TE->ReuseShuffleIndices.empty())
14753 if (!Op1TE->isGather() || !Op2TE->isGather())
14756 auto *
Cmp = CmpTE->getMainOp();
14759 if (!
match(Cmp, MatchCmp))
14761 CmpPredicate MainPred = Pred;
14764 for (
const auto [Idx, V] :
enumerate(CmpTE->Scalars)) {
14765 if (!
match(V, MatchCmp))
14771 if (!
V->hasOneUse())
14776 if (InversedCmpsIndices.
empty())
14783 TTI->getCmpSelInstrCost(CmpTE->getOpcode(), VecTy, CmpTy, MainPred,
14784 CostKind, getOperandInfo(CmpTE->getOperand(0)),
14785 getOperandInfo(CmpTE->getOperand(1)));
14789 true,
false, CostKind);
14790 for (
Value *V : CmpTE->Scalars) {
14794 BVCost += TTI->getInstructionCost(
I, CostKind);
14796 return VecCost < BVCost;
14799bool BoUpSLP::matchesSelectOfBits(
const TreeEntry &SelectTE)
const {
14800 assert(SelectTE.hasState() && SelectTE.getOpcode() == Instruction::Select &&
14801 "Expected select node.");
14802 if (DL->isBigEndian())
14804 if (!SelectTE.ReorderIndices.empty() || !SelectTE.ReuseShuffleIndices.empty())
14806 if (!UserIgnoreList || SelectTE.Idx != 0)
14808 if (
any_of(SelectTE.Scalars, [](
Value *V) { return !V->hasOneUse(); }))
14811 if (
any_of(*UserIgnoreList,
14814 const TreeEntry *Op1TE = getOperandEntry(&SelectTE, 1);
14815 const TreeEntry *Op2TE = getOperandEntry(&SelectTE, 2);
14816 if (!Op1TE->isGather() || !Op2TE->isGather())
14819 if (!Op1TE->ReorderIndices.empty() || !Op1TE->ReuseShuffleIndices.empty() ||
14820 !Op2TE->ReuseShuffleIndices.empty())
14822 Type *ScalarTy = Op1TE->Scalars.front()->getType();
14826 if (
any_of(Op2TE->Scalars, [](
Value *V) { return !match(V, m_ZeroInt()); }))
14831 return !(match(P.value(), m_ConstantInt(V)) && isPowerOf2_64(V) &&
14832 Log2_64(V) == P.index());
14836 auto *DstTy = IntegerType::getIntNTy(ScalarTy->
getContext(),
14837 SelectTE.getVectorFactor());
14842 auto It = MinBWs.find(&SelectTE);
14843 if (It != MinBWs.end()) {
14844 auto *EffectiveScalarTy =
14851 if (DstTy != ScalarTy) {
14852 BitcastCost += TTI->getCastInstrCost(Instruction::ZExt, ScalarTy, DstTy,
14857 TTI->getCmpSelInstrCost(Instruction::Select, VecTy, CmpTy,
14859 getOperandInfo(Op1TE->Scalars),
14860 getOperandInfo(Op2TE->Scalars)) +
14861 TTI->getArithmeticReductionCost(Instruction::Or, VecTy, FMF, CostKind);
14862 return BitcastCost <= SelectCost;
14866 BaseGraphSize = VectorizableTree.size();
14868 class GraphTransformModeRAAI {
14869 bool &SavedIsGraphTransformMode;
14872 GraphTransformModeRAAI(
bool &IsGraphTransformMode)
14873 : SavedIsGraphTransformMode(IsGraphTransformMode) {
14874 IsGraphTransformMode =
true;
14876 ~GraphTransformModeRAAI() { SavedIsGraphTransformMode =
false; }
14877 } TransformContext(IsGraphTransformMode);
14890 I2->getOperand(
Op));
14891 return all_of(Candidates, [
this](
14892 ArrayRef<std::pair<Value *, Value *>> Cand) {
14894 [](
const std::pair<Value *, Value *> &
P) {
14904 TreeEntry &E = *VectorizableTree[Idx];
14906 reorderGatherNode(E);
14911 constexpr unsigned VFLimit = 16;
14912 bool ForceLoadGather =
14913 count_if(VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &TE) {
14914 return TE->isGather() && TE->hasState() &&
14915 TE->getOpcode() == Instruction::Load &&
14916 TE->getVectorFactor() < VFLimit;
14922 return TE->isSame(VL) ||
all_of(VL, [&](
Value *V) {
14931 auto CheckForSameVectorNodes = [&](
const TreeEntry &E) {
14932 if (E.hasState()) {
14934 !TEs.
empty() &&
any_of(TEs, [&](
const TreeEntry *TE) {
14935 return AreReusedScalars(TE, E.Scalars, [&](
Value *V) {
14936 ArrayRef<TreeEntry *> VTEs = getTreeEntries(V);
14937 return !VTEs.empty() && any_of(VTEs, [&](const TreeEntry *TE) {
14938 return is_contained(TEs, TE);
14945 !TEs.
empty() &&
any_of(TEs, [&](
const TreeEntry *TE) {
14946 return AreReusedScalars(TE, E.Scalars, [&](
Value *V) {
14947 ArrayRef<TreeEntry *> VTEs = getSplitTreeEntries(V);
14948 return !VTEs.empty() && any_of(VTEs, [&](const TreeEntry *TE) {
14949 return is_contained(TEs, TE);
14957 if (It != E.Scalars.end()) {
14959 !TEs.empty() &&
any_of(TEs, [&](
const TreeEntry *TE) {
14960 return AreReusedScalars(TE, E.Scalars, [&](
Value *V) {
14961 ArrayRef<TreeEntry *> VTEs = getSplitTreeEntries(V);
14962 return !VTEs.empty() && any_of(VTEs, [&](const TreeEntry *TE) {
14963 return is_contained(TEs, TE);
14973 for (
unsigned Idx :
seq<unsigned>(BaseGraphSize)) {
14974 TreeEntry &
E = *VectorizableTree[Idx];
14975 if (
E.isGather()) {
14978 unsigned MinVF =
getMinVF(2 * Sz);
14981 if (VL.
size() <= 2 || LoadEntriesToVectorize.contains(Idx) ||
14982 !(!
E.hasState() ||
E.getOpcode() == Instruction::Load ||
14988 if (ForceLoadGather &&
E.hasState() &&
E.getOpcode() == Instruction::Load)
14991 if (CheckForSameVectorNodes(
E))
14995 unsigned StartIdx = 0;
14996 unsigned End = VL.
size();
14997 SmallBitVector Processed(End);
15002 if (StartIdx + VF > End)
15005 bool AllStrided =
true;
15011 for (
unsigned Cnt = StartIdx; Cnt < End; Cnt += VF) {
15012 const unsigned SliceVF = std::min(VF, End - Cnt);
15019 !getSameValuesTreeEntry(Slice.
front(), Slice,
true))
15026 bool IsSplat =
isSplat(Slice);
15027 bool IsTwoRegisterSplat =
true;
15028 if (IsSplat && VF == 2) {
15033 IsTwoRegisterSplat = NumRegs2VF == 2;
15035 if (Slices.
empty() || !IsSplat || !IsTwoRegisterSplat ||
15048 std::optional<bool> MainOpIsCheap;
15049 auto IsMainOpCheap = [&] {
15050 if (!MainOpIsCheap)
15052 TTI->getInstructionCost(S.
getMainOp(), CostKind) <
15054 return *MainOpIsCheap;
15058 if ((!UserIgnoreList ||
E.Idx != 0) && IsMainOpCheap() &&
15066 if (S.
getOpcode() == Instruction::Load) {
15071 PointerOps, SPtrInfo);
15082 if (UserIgnoreList &&
E.Idx == 0)
15087 }
else if (S.
getOpcode() == Instruction::ExtractElement ||
15088 (IsMainOpCheap() &&
15089 !CheckOperandsProfitability(
15106 if (VF == 2 && AllStrided && Slices.
size() > 2)
15108 auto AddCombinedNode = [&](
unsigned Idx,
unsigned Cnt,
unsigned Sz) {
15109 E.CombinedEntriesWithIndices.emplace_back(Idx, Cnt);
15110 Processed.set(Cnt, Cnt + Sz);
15111 if (StartIdx == Cnt)
15112 StartIdx = Cnt + Sz;
15113 if (End == Cnt + Sz)
15116 for (
auto [Cnt, Sz] : Slices) {
15118 const TreeEntry *SameTE =
nullptr;
15120 It != Slice.
end()) {
15122 SameTE = getSameValuesTreeEntry(*It, Slice);
15124 unsigned PrevSize = VectorizableTree.size();
15125 [[maybe_unused]]
unsigned PrevEntriesSize =
15126 LoadEntriesToVectorize.size();
15127 buildTreeRec(Slice, 0,
EdgeInfo(&
E, UINT_MAX));
15128 if (PrevSize + 1 == VectorizableTree.size() && !SameTE &&
15129 VectorizableTree[PrevSize]->isGather() &&
15130 VectorizableTree[PrevSize]->hasState() &&
15131 VectorizableTree[PrevSize]->getOpcode() !=
15132 Instruction::ExtractElement &&
15134 if (UserIgnoreList &&
E.Idx == 0 && VF == 2)
15136 VectorizableTree.pop_back();
15137 assert(PrevEntriesSize == LoadEntriesToVectorize.size() &&
15138 "LoadEntriesToVectorize expected to remain the same");
15141 AddCombinedNode(PrevSize, Cnt, Sz);
15145 if (
E.CombinedEntriesWithIndices.empty() && !
E.ReorderIndices.empty()) {
15146 SmallVector<int>
Mask(
E.ReorderIndices.begin(),
E.ReorderIndices.end());
15148 E.ReorderIndices.clear();
15153 switch (
E.getOpcode()) {
15154 case Instruction::Load: {
15157 if (
E.State != TreeEntry::Vectorize)
15159 Type *ScalarTy =
E.getMainOp()->getType();
15166 TTI->isLegalStridedLoadStore(VecTy, CommonAlignment)) {
15167 SmallVector<int>
Mask;
15171 TTI->getMemoryOpCost(Instruction::Load, VecTy, BaseLI->getAlign(),
15172 BaseLI->getPointerAddressSpace(), CostKind,
15176 MemIntrinsicCostAttributes(Intrinsic::experimental_vp_strided_load,
15177 VecTy, BaseLI->getPointerOperand(),
15178 false, CommonAlignment,
15185 ->getPointerOperand()
15188 SPtrInfo.
StrideVal = ConstantInt::get(StrideTy, 1);
15189 SPtrInfo.Ty = VecTy;
15190 TreeEntryToStridedPtrInfoMap[&
E] = SPtrInfo;
15191 E.State = TreeEntry::StridedVectorize;
15196 case Instruction::Store: {
15197 if (
E.State == TreeEntry::ExpandVectorize)
15207 TTI->isLegalStridedLoadStore(VecTy, CommonAlignment)) {
15208 SmallVector<int>
Mask;
15212 TTI->getMemoryOpCost(Instruction::Store, VecTy, BaseSI->getAlign(),
15213 BaseSI->getPointerAddressSpace(), CostKind,
15217 MemIntrinsicCostAttributes(Intrinsic::experimental_vp_strided_store,
15218 VecTy, BaseSI->getPointerOperand(),
15219 false, CommonAlignment,
15222 if (StridedCost < OriginalVecCost) {
15225 E.State = TreeEntry::StridedVectorize;
15227 ->getPointerOperand()
15231 SPtrInfo.Ty = VecTy;
15232 TreeEntryToStridedPtrInfoMap[&
E] = SPtrInfo;
15234 }
else if (!
E.ReorderIndices.empty()) {
15236 auto IsInterleaveMask = [&, &TTI = *TTI](ArrayRef<int>
Mask) {
15238 assert(
Mask.size() > 1 &&
"Expected mask greater than 1 element.");
15239 if (
Mask.size() < 4)
15243 Mask, Factor, VecTy->getElementCount().getFixedValue()) &&
15244 TTI.isLegalInterleavedAccessType(
15245 VecTy, Factor, BaseSI->getAlign(),
15246 BaseSI->getPointerAddressSpace()))
15252 SmallVector<int>
Mask(
E.ReorderIndices.begin(),
E.ReorderIndices.end());
15253 unsigned InterleaveFactor = IsInterleaveMask(Mask);
15254 if (InterleaveFactor != 0)
15255 E.setInterleave(InterleaveFactor);
15259 case Instruction::Select: {
15260 if (
E.State != TreeEntry::Vectorize)
15265 E.CombinedOp = TreeEntry::MinMax;
15266 TreeEntry *CondEntry = getOperandEntry(&
E, 0);
15267 if (SelectOnly && CondEntry->UserTreeIndex &&
15268 CondEntry->State == TreeEntry::Vectorize) {
15270 CondEntry->State = TreeEntry::CombinedVectorize;
15275 SmallVector<unsigned> InversedCmpsIndices;
15276 if (matchesInversedZExtSelect(
E, InversedCmpsIndices)) {
15277 auto *CmpTE = getOperandEntry(&
E, 0);
15278 auto *Op1TE = getOperandEntry(&
E, 1);
15279 auto *Op2TE = getOperandEntry(&
E, 2);
15281 CmpTE->setOperations(
15282 InstructionsState(CmpTE->getMainOp(), CmpTE->getMainOp()));
15285 auto UpdateGatherEntry = [&](TreeEntry *OldTE, TreeEntry *NewTE,
15289 auto It = ValueToGatherNodes.find(V);
15290 assert(It != ValueToGatherNodes.end() &&
15291 "Expected to find the value in the map.");
15292 auto &
C = It->getSecond();
15299 for (
const unsigned Idx : InversedCmpsIndices) {
15300 Value *
V1 = Op1TE->Scalars[Idx];
15301 Value *V2 = Op2TE->Scalars[Idx];
15302 std::swap(Op1TE->Scalars[Idx], Op2TE->Scalars[Idx]);
15304 UpdateGatherEntry(Op1TE, Op2TE,
V1);
15305 UpdateGatherEntry(Op2TE, Op1TE, V2);
15307 OperandsToTreeEntry.emplace_or_assign(std::make_pair(&
E, 1), Op1TE);
15308 OperandsToTreeEntry.emplace_or_assign(std::make_pair(&
E, 2), Op2TE);
15311 if (matchesSelectOfBits(
E)) {
15313 const TreeEntry::CombinedOpcode
Code = TreeEntry::ReducedCmpBitcast;
15314 E.CombinedOp =
Code;
15315 auto *Op1TE = getOperandEntry(&
E, 1);
15316 auto *Op2TE = getOperandEntry(&
E, 2);
15317 Op1TE->State = TreeEntry::CombinedVectorize;
15318 Op1TE->CombinedOp =
Code;
15319 Op2TE->State = TreeEntry::CombinedVectorize;
15320 Op2TE->CombinedOp =
Code;
15325 case Instruction::FSub:
15326 case Instruction::FAdd: {
15329 if (
E.State != TreeEntry::Vectorize ||
15330 !
E.getOperations().isAddSubLikeOp() ||
15331 E.getOperations().isAltShuffle() ||
E.getNumOperands() != 2)
15333 const TreeEntry *
LHS = getOperandEntry(&
E, 0);
15334 const TreeEntry *
RHS = getOperandEntry(&
E, 1);
15335 auto IsOneUseVectorFMulOperand = [](
const TreeEntry *
TE) {
15336 return TE->State == TreeEntry::Vectorize &&
15337 TE->ReorderIndices.empty() &&
TE->ReuseShuffleIndices.empty() &&
15338 TE->getOpcode() == Instruction::FMul && !
TE->isAltShuffle() &&
15340 return (TE->hasCopyableElements() &&
15341 TE->isCopyableElement(V)) ||
15345 if (!IsOneUseVectorFMulOperand(
LHS) &&
15346 (
E.getOpcode() == Instruction::FSub ||
15347 !IsOneUseVectorFMulOperand(
RHS)))
15354 E.CombinedOp = TreeEntry::FMulAdd;
15355 TreeEntry *FMulEntry = getOperandEntry(&
E, 0);
15356 if (FMulEntry->UserTreeIndex &&
15357 FMulEntry->State == TreeEntry::Vectorize) {
15359 FMulEntry->State = TreeEntry::CombinedVectorize;
15363 case Instruction::Shl: {
15365 if (
E.getNumOperands() != 2)
15367 if (
E.Idx != 0 || DL->isBigEndian())
15369 if (!UserIgnoreList)
15379 if (!matchesShlZExt(
E, Order, IsBSwap, ForLoads))
15382 TreeEntry::CombinedOpcode
Code =
15383 IsBSwap ? (ForLoads ? TreeEntry::ReducedBitcastBSwapLoads
15384 : TreeEntry::ReducedBitcastBSwap)
15385 : (ForLoads ? TreeEntry::ReducedBitcastLoads
15386 : TreeEntry::ReducedBitcast);
15387 E.CombinedOp =
Code;
15388 E.ReorderIndices = std::move(Order);
15389 TreeEntry *ZExtEntry = getOperandEntry(&
E, 0);
15390 assert(ZExtEntry->UserTreeIndex &&
15391 ZExtEntry->State == TreeEntry::Vectorize &&
15392 ZExtEntry->getOpcode() == Instruction::ZExt &&
15393 "Expected ZExt node.");
15395 ZExtEntry->State = TreeEntry::CombinedVectorize;
15396 ZExtEntry->CombinedOp =
Code;
15398 TreeEntry *LoadsEntry = getOperandEntry(ZExtEntry, 0);
15399 assert(LoadsEntry->UserTreeIndex &&
15400 LoadsEntry->State == TreeEntry::Vectorize &&
15401 LoadsEntry->getOpcode() == Instruction::Load &&
15402 "Expected Load node.");
15404 LoadsEntry->State = TreeEntry::CombinedVectorize;
15405 LoadsEntry->CombinedOp =
Code;
15407 TreeEntry *ConstEntry = getOperandEntry(&
E, 1);
15408 assert(ConstEntry->UserTreeIndex && ConstEntry->isGather() &&
15409 "Expected ZExt node.");
15411 ConstEntry->State = TreeEntry::CombinedVectorize;
15412 ConstEntry->CombinedOp =
Code;
15420 if (LoadEntriesToVectorize.empty()) {
15422 if (VectorizableTree.size() <= 1 &&
getRootNode().hasState() &&
15426 constexpr unsigned SmallTree = 3;
15427 constexpr unsigned SmallVF = 2;
15428 if ((VectorizableTree.size() <= SmallTree &&
15430 (VectorizableTree.size() <= 2 && UserIgnoreList))
15437 [](
const std::unique_ptr<TreeEntry> &TE) {
15438 return TE->isGather() &&
TE->hasState() &&
15439 TE->getOpcode() == Instruction::Load &&
15447 SmallMapVector<std::tuple<BasicBlock *, Value *, Type *>,
15451 for (std::unique_ptr<TreeEntry> &TE : VectorizableTree) {
15452 TreeEntry &
E = *
TE;
15453 if (
E.isGather() &&
15454 ((
E.hasState() &&
E.getOpcode() == Instruction::Load) ||
15455 (!
E.hasState() &&
any_of(
E.Scalars,
15457 return isa<LoadInst>(V) &&
15458 !isVectorized(V) &&
15459 !isDeleted(cast<Instruction>(V));
15462 for (
Value *V :
E.Scalars) {
15469 *
this, V, *DL, *SE, *TTI,
15470 GatheredLoads[std::make_tuple(
15478 if (!GatheredLoads.
empty())
15479 tryToVectorizeGatheredLoads(GatheredLoads);
15489 bool IsFinalized =
false;
15515 bool SameNodesEstimated =
true;
15518 if (Ty->getScalarType()->isPointerTy()) {
15522 DL.getTypeStoreSizeInBits(Ty->getScalarType()))),
15523 Ty->getScalarType());
15541 assert(It != VL.
end() &&
"Expected at least one non-undef value.");
15544 count(VL, *It) > 1 &&
15546 if (!NeedShuffle) {
15549 return TTI.getShuffleCost(
15554 return TTI.getVectorInstrCost(Instruction::InsertElement, VecTy,
15555 CostKind, std::distance(VL.
begin(), It),
15561 return isa<PoisonValue>(V) ? PoisonMaskElem : 0;
15564 TTI.getVectorInstrCost(Instruction::InsertElement, VecTy, CostKind, 0,
15567 VecTy, CostKind, ShuffleMask,
15571 return GatherCost +
15574 : R.getGatherCost(Gathers, !Root && VL.
equals(Gathers),
15582 ArrayRef<std::optional<TTI::ShuffleKind>> ShuffleKinds,
15583 unsigned NumParts) {
15584 assert(VL.
size() > NumParts &&
"Unexpected scalarized shuffle.");
15592 return std::max(Sz, VecTy->getNumElements());
15599 -> std::optional<TTI::ShuffleKind> {
15600 if (NumElts <= EltsPerVector)
15601 return std::nullopt;
15606 return std::min(S,
I);
15609 int OffsetReg1 = OffsetReg0;
15613 int FirstRegId = -1;
15614 Indices.assign(1, OffsetReg0);
15618 int Idx =
I - OffsetReg0;
15620 (Idx / NumElts) * NumParts + (Idx % NumElts) / EltsPerVector;
15621 if (FirstRegId < 0)
15622 FirstRegId = RegId;
15623 RegIndices.
insert(RegId);
15624 if (RegIndices.
size() > 2)
15625 return std::nullopt;
15626 if (RegIndices.
size() == 2) {
15628 if (Indices.
size() == 1) {
15631 std::next(Mask.begin(), Pos), Mask.end(), INT_MAX,
15632 [&](
int S,
int I) {
15633 if (I == PoisonMaskElem)
15635 int RegId = ((I - OffsetReg0) / NumElts) * NumParts +
15636 ((I - OffsetReg0) % NumElts) / EltsPerVector;
15637 if (RegId == FirstRegId)
15639 return std::min(S, I);
15642 unsigned Index = OffsetReg1 % NumElts;
15643 Indices.push_back(Index);
15644 SubVecSizes.push_back(std::min(NumElts - Index, EltsPerVector));
15646 Idx =
I - OffsetReg1;
15648 I = (Idx % NumElts) % EltsPerVector +
15649 (RegId == FirstRegId ? 0 : EltsPerVector);
15651 return ShuffleKind;
15659 if (!ShuffleKinds[Part])
15662 Part * EltsPerVector,
getNumElems(Mask.size(), EltsPerVector, Part));
15667 std::optional<TTI::ShuffleKind> RegShuffleKind =
15668 CheckPerRegistersShuffle(SubMask, Indices, SubVecSizes);
15669 if (!RegShuffleKind) {
15672 MaskSlice, std::max<unsigned>(NumElts, MaskSlice.
size())))
15674 TTI, *ShuffleKinds[Part],
15682 TTI, *RegShuffleKind,
15687 *R.TTI, VL.
front()->getType(),
alignTo(NumElts, EltsPerVector),
15689 for (
const auto [Idx, SubVecSize] :
zip(Indices, SubVecSizes)) {
15690 assert((Idx + SubVecSize) <= BaseVF &&
15691 "SK_ExtractSubvector index out of range");
15704 CostKind, SubMask);
15705 if (OriginalCost < Cost)
15706 Cost = OriginalCost;
15713 void estimateNodesPermuteCost(
const TreeEntry &E1,
const TreeEntry *E2,
15715 unsigned SliceSize) {
15716 if (SameNodesEstimated) {
15722 if ((InVectors.size() == 2 &&
15726 unsigned Limit =
getNumElems(Mask.size(), SliceSize, Part);
15729 "Expected all poisoned elements.");
15731 copy(SubMask, std::next(CommonMask.begin(), SliceSize * Part));
15736 Cost += createShuffle(InVectors.front(),
15737 InVectors.size() == 1 ?
nullptr : InVectors.back(),
15739 transformMaskAfterShuffle(CommonMask, CommonMask);
15740 }
else if (InVectors.size() == 2) {
15741 Cost += createShuffle(InVectors.front(), InVectors.back(), CommonMask);
15742 transformMaskAfterShuffle(CommonMask, CommonMask);
15744 SameNodesEstimated =
false;
15745 if (!E2 && InVectors.size() == 1) {
15746 unsigned VF = E1.getVectorFactor();
15748 VF = std::max(VF, getVF(
V1));
15751 VF = std::max(VF, E->getVectorFactor());
15753 for (
unsigned Idx = 0, Sz = CommonMask.size(); Idx < Sz; ++Idx)
15755 CommonMask[Idx] = Mask[Idx] + VF;
15756 Cost += createShuffle(InVectors.front(), &E1, CommonMask);
15757 transformMaskAfterShuffle(CommonMask, CommonMask);
15759 auto P = InVectors.front();
15760 Cost += createShuffle(&E1, E2, Mask);
15761 unsigned VF = Mask.size();
15767 VF = std::max(VF, E->getVectorFactor());
15769 for (
unsigned Idx = 0, Sz = CommonMask.size(); Idx < Sz; ++Idx)
15771 CommonMask[Idx] = Idx + (InVectors.empty() ? 0 : VF);
15772 Cost += createShuffle(
P, InVectors.front(), CommonMask);
15773 transformMaskAfterShuffle(CommonMask, CommonMask);
15777 class ShuffleCostBuilder {
15781 static bool isEmptyOrIdentity(
ArrayRef<int> Mask,
unsigned VF) {
15783 return Mask.empty() ||
15784 (VF == Mask.size() &&
15794 ~ShuffleCostBuilder() =
default;
15800 if (isEmptyOrIdentity(Mask, VF))
15810 if (isEmptyOrIdentity(Mask, VF))
15820 void resizeToMatch(
Value *&,
Value *&)
const {}
15830 ShuffleCostBuilder Builder(TTI, CostKind);
15833 unsigned CommonVF = Mask.size();
15835 auto GetNodeMinBWAffectedCost = [&](
const TreeEntry &E,
15839 Type *EScalarTy = E.Scalars.front()->getType();
15840 bool IsSigned =
true;
15841 if (
auto It = R.MinBWs.find(&E); It != R.MinBWs.end()) {
15843 IsSigned = It->second.second;
15845 if (EScalarTy != ScalarTy) {
15846 unsigned CastOpcode = Instruction::Trunc;
15847 unsigned DstSz = R.DL->getTypeSizeInBits(ScalarTy);
15848 unsigned SrcSz = R.DL->getTypeSizeInBits(EScalarTy);
15850 CastOpcode = IsSigned ? Instruction::SExt : Instruction::ZExt;
15851 return TTI.getCastInstrCost(CastOpcode,
getWidenedType(ScalarTy, VF),
15861 Type *EScalarTy = VecTy->getElementType();
15862 if (EScalarTy != ScalarTy) {
15864 unsigned CastOpcode = Instruction::Trunc;
15865 unsigned DstSz = R.DL->getTypeSizeInBits(ScalarTy);
15866 unsigned SrcSz = R.DL->getTypeSizeInBits(EScalarTy);
15868 CastOpcode = IsSigned ? Instruction::SExt : Instruction::ZExt;
15869 return TTI.getCastInstrCost(
15875 if (!
V1 && !V2 && !P2.isNull()) {
15878 unsigned VF = E->getVectorFactor();
15880 CommonVF = std::max(VF, E2->getVectorFactor());
15883 return Idx < 2 * static_cast<int>(CommonVF);
15885 "All elements in mask must be less than 2 * CommonVF.");
15886 if (E->Scalars.size() == E2->Scalars.size()) {
15890 for (
int &Idx : CommonMask) {
15893 if (Idx <
static_cast<int>(CommonVF) && !EMask.
empty())
15895 else if (Idx >=
static_cast<int>(CommonVF))
15896 Idx = (E2Mask.
empty() ? Idx - CommonVF : E2Mask[Idx - CommonVF]) +
15900 CommonVF = E->Scalars.size();
15901 ExtraCost += GetNodeMinBWAffectedCost(*E, CommonVF) +
15902 GetNodeMinBWAffectedCost(*E2, CommonVF);
15904 ExtraCost += GetNodeMinBWAffectedCost(*E, E->getVectorFactor()) +
15905 GetNodeMinBWAffectedCost(*E2, E2->getVectorFactor());
15908 V2 = getAllOnesValue(*R.DL,
getWidenedType(ScalarTy, CommonVF));
15909 }
else if (!
V1 && P2.isNull()) {
15912 unsigned VF = E->getVectorFactor();
15916 [=](
int Idx) {
return Idx < static_cast<int>(CommonVF); }) &&
15917 "All elements in mask must be less than CommonVF.");
15918 if (E->Scalars.size() == Mask.size() && VF != Mask.size()) {
15920 assert(!EMask.
empty() &&
"Expected non-empty common mask.");
15921 for (
int &Idx : CommonMask) {
15925 CommonVF = E->Scalars.size();
15926 }
else if (
unsigned Factor = E->getInterleaveFactor();
15927 Factor > 0 && E->Scalars.size() != Mask.size() &&
15931 std::iota(CommonMask.begin(), CommonMask.end(), 0);
15933 ExtraCost += GetNodeMinBWAffectedCost(*E, CommonVF);
15936 if (!E->ReorderIndices.empty() && CommonVF == E->ReorderIndices.size() &&
15937 CommonVF == CommonMask.size() &&
15939 [](
const auto &&
P) {
15941 static_cast<unsigned>(
P.value()) !=
P.index();
15947 addMask(CommonMask, ReorderMask);
15949 }
else if (
V1 && P2.isNull()) {
15951 ExtraCost += GetValueMinBWAffectedCost(
V1);
15952 CommonVF = getVF(
V1);
15955 [=](
int Idx) {
return Idx < static_cast<int>(CommonVF); }) &&
15956 "All elements in mask must be less than CommonVF.");
15957 }
else if (
V1 && !V2) {
15959 unsigned VF = getVF(
V1);
15961 CommonVF = std::max(VF, E2->getVectorFactor());
15964 return Idx < 2 * static_cast<int>(CommonVF);
15966 "All elements in mask must be less than 2 * CommonVF.");
15967 if (E2->Scalars.size() == VF && VF != CommonVF) {
15969 assert(!E2Mask.
empty() &&
"Expected non-empty common mask.");
15970 for (
int &Idx : CommonMask) {
15973 if (Idx >=
static_cast<int>(CommonVF))
15974 Idx = E2Mask[Idx - CommonVF] + VF;
15978 ExtraCost += GetValueMinBWAffectedCost(
V1);
15980 ExtraCost += GetNodeMinBWAffectedCost(
15981 *E2, std::min(CommonVF, E2->getVectorFactor()));
15982 V2 = getAllOnesValue(*R.DL,
getWidenedType(ScalarTy, CommonVF));
15983 }
else if (!
V1 && V2) {
15985 unsigned VF = getVF(V2);
15987 CommonVF = std::max(VF, E1->getVectorFactor());
15990 return Idx < 2 * static_cast<int>(CommonVF);
15992 "All elements in mask must be less than 2 * CommonVF.");
15993 if (E1->Scalars.size() == VF && VF != CommonVF) {
15995 assert(!E1Mask.
empty() &&
"Expected non-empty common mask.");
15996 for (
int &Idx : CommonMask) {
15999 if (Idx >=
static_cast<int>(CommonVF))
16000 Idx = E1Mask[Idx - CommonVF] + VF;
16006 ExtraCost += GetNodeMinBWAffectedCost(
16007 *E1, std::min(CommonVF, E1->getVectorFactor()));
16009 ExtraCost += GetValueMinBWAffectedCost(V2);
16010 V2 = getAllOnesValue(*R.DL,
getWidenedType(ScalarTy, CommonVF));
16012 assert(
V1 && V2 &&
"Expected both vectors.");
16013 unsigned VF = getVF(
V1);
16014 CommonVF = std::max(VF, getVF(V2));
16017 return Idx < 2 * static_cast<int>(CommonVF);
16019 "All elements in mask must be less than 2 * CommonVF.");
16021 GetValueMinBWAffectedCost(
V1) + GetValueMinBWAffectedCost(V2);
16024 V2 = getAllOnesValue(*R.DL,
getWidenedType(ScalarTy, CommonVF));
16029 V2 = getAllOnesValue(*R.DL,
getWidenedType(ScalarTy, CommonVF));
16032 InVectors.front() =
16034 if (InVectors.size() == 2)
16035 InVectors.pop_back();
16036 return ExtraCost + BaseShuffleAnalysis::createShuffle<InstructionCost>(
16037 V1, V2, CommonMask, Builder, ScalarTy, VL);
16044 : BaseShuffleAnalysis(ScalarTy), TTI(TTI),
16045 VectorizedVals(VectorizedVals.begin(), VectorizedVals.end()), R(R),
16046 CheckedExtracts(CheckedExtracts), CostKind(R.
getCostKind()) {}
16048 ArrayRef<std::optional<TTI::ShuffleKind>> ShuffleKinds,
16049 unsigned NumParts,
bool &UseVecBaseAsInput) {
16050 UseVecBaseAsInput =
false;
16053 Value *VecBase =
nullptr;
16055 if (!E->ReorderIndices.empty()) {
16057 E->ReorderIndices.end());
16062 bool PrevNodeFound =
any_of(
16063 ArrayRef(R.VectorizableTree).take_front(E->Idx),
16064 [&](
const std::unique_ptr<TreeEntry> &TE) {
16065 return ((TE->hasState() && !TE->isAltShuffle() &&
16066 TE->getOpcode() == Instruction::ExtractElement) ||
16068 all_of(enumerate(TE->Scalars), [&](auto &&Data) {
16069 return VL.size() > Data.index() &&
16070 (Mask[Data.index()] == PoisonMaskElem ||
16071 isa<UndefValue>(VL[Data.index()]) ||
16072 Data.value() == VL[Data.index()]);
16080 ArrayRef<int> SubMask = Mask.slice(Part * SliceSize, Limit);
16094 VecBase = EE->getVectorOperand();
16095 UniqueBases.
insert(VecBase);
16097 if (!CheckedExtracts.
insert(V).second ||
16100 [&](
const TreeEntry *TE) {
16101 return R.DeletedNodes.contains(TE) ||
16102 R.TransformedToGatherNodes.contains(TE);
16104 (E->UserTreeIndex && E->UserTreeIndex.EdgeIdx == UINT_MAX &&
16105 !R.isVectorized(EE) &&
16107 count_if(E->UserTreeIndex.UserTE->Scalars,
16108 [&](
Value *V) { return V == EE; })) ||
16111 return isa<GetElementPtrInst>(U) &&
16112 !R.areAllUsersVectorized(cast<Instruction>(U),
16120 unsigned Idx = *EEIdx;
16122 if (EE->hasOneUse() || !PrevNodeFound) {
16128 Cost -=
TTI.getExtractWithExtendCost(
16132 Cost +=
TTI.getCastInstrCost(
16138 APInt &DemandedElts =
16139 VectorOpsToExtracts
16142 .first->getSecond();
16143 DemandedElts.
setBit(Idx);
16146 for (
const auto &[Vec, DemandedElts] : VectorOpsToExtracts)
16148 DemandedElts,
false,
16156 if (!PrevNodeFound)
16157 Cost += computeExtractCost(VL, Mask, ShuffleKinds, NumParts);
16160 transformMaskAfterShuffle(CommonMask, CommonMask);
16161 SameNodesEstimated =
false;
16162 if (NumParts != 1 && UniqueBases.
size() != 1) {
16163 UseVecBaseAsInput =
true;
16171 std::optional<InstructionCost>
16175 return std::nullopt;
16179 IsFinalized =
false;
16180 CommonMask.clear();
16183 VectorizedVals.clear();
16184 SameNodesEstimated =
true;
16191 return Idx < static_cast<int>(E1.getVectorFactor());
16193 "Expected single vector shuffle mask.");
16197 if (InVectors.empty()) {
16198 CommonMask.assign(Mask.begin(), Mask.end());
16199 InVectors.assign({&E1, &E2});
16202 assert(!CommonMask.empty() &&
"Expected non-empty common mask.");
16204 unsigned NumParts =
16208 unsigned Part = std::distance(Mask.begin(), It) / SliceSize;
16209 estimateNodesPermuteCost(E1, &E2, Mask, Part, SliceSize);
16213 if (InVectors.empty()) {
16214 CommonMask.assign(Mask.begin(), Mask.end());
16215 InVectors.assign(1, &E1);
16218 assert(!CommonMask.empty() &&
"Expected non-empty common mask.");
16220 unsigned NumParts =
16224 unsigned Part = std::distance(Mask.begin(), It) / SliceSize;
16225 estimateNodesPermuteCost(E1,
nullptr, Mask, Part, SliceSize);
16226 if (!SameNodesEstimated && InVectors.size() == 1)
16227 InVectors.emplace_back(&E1);
16233 assert(InVectors.size() == 1 &&
16240 ->getOrdered(
P.index()));
16241 return EI->getVectorOperand() ==
V1 ||
16242 EI->getVectorOperand() == V2;
16244 "Expected extractelement vectors.");
16250 if (InVectors.empty()) {
16251 assert(CommonMask.empty() && !ForExtracts &&
16252 "Expected empty input mask/vectors.");
16253 CommonMask.assign(Mask.begin(), Mask.end());
16254 InVectors.assign(1,
V1);
16260 !CommonMask.empty() &&
16264 ->getOrdered(
P.index());
16266 return P.value() == Mask[
P.index()] ||
16271 return EI->getVectorOperand() ==
V1;
16273 "Expected only tree entry for extractelement vectors.");
16276 assert(!InVectors.empty() && !CommonMask.empty() &&
16277 "Expected only tree entries from extracts/reused buildvectors.");
16278 unsigned VF = getVF(
V1);
16279 if (InVectors.size() == 2) {
16280 Cost += createShuffle(InVectors.front(), InVectors.back(), CommonMask);
16281 transformMaskAfterShuffle(CommonMask, CommonMask);
16282 VF = std::max<unsigned>(VF, CommonMask.size());
16283 }
else if (
const auto *InTE =
16284 InVectors.front().dyn_cast<
const TreeEntry *>()) {
16285 VF = std::max(VF, InTE->getVectorFactor());
16289 ->getNumElements());
16291 InVectors.push_back(
V1);
16292 for (
unsigned Idx = 0, Sz = CommonMask.size(); Idx < Sz; ++Idx)
16294 CommonMask[Idx] = Mask[Idx] + VF;
16297 Value *Root =
nullptr) {
16298 Cost += getBuildVectorCost(VL, Root);
16300 if (BVValues->empty() && InVectors.empty())
16301 BVValues->assign(VL.
begin(), VL.
end());
16308 unsigned VF = VL.
size();
16310 VF = std::min(VF, MaskVF);
16311 Type *VLScalarTy = VL.
front()->getType();
16335 getAllOnesValue(*R.DL, ScalarTy->getScalarType()));
16341 ArrayRef<std::pair<const TreeEntry *, unsigned>> SubVectors,
16346 IsFinalized =
true;
16349 if (InVectors.
size() == 2)
16350 Cost += createShuffle(Vec, InVectors.
back(), CommonMask);
16352 Cost += createShuffle(Vec,
nullptr, CommonMask);
16353 transformMaskAfterShuffle(CommonMask, CommonMask);
16355 "Expected vector length for the final value before action.");
16358 Cost += createShuffle(
V1, V2, Mask);
16361 InVectors.
front() = V;
16363 if (!SubVectors.empty()) {
16365 if (InVectors.
size() == 2)
16366 Cost += createShuffle(Vec, InVectors.
back(), CommonMask);
16368 Cost += createShuffle(Vec,
nullptr, CommonMask);
16369 transformMaskAfterShuffle(CommonMask, CommonMask);
16371 if (!SubVectorsMask.
empty()) {
16373 "Expected same size of masks for subvectors and common mask.");
16375 copy(SubVectorsMask, SVMask.begin());
16376 for (
auto [I1, I2] :
zip(SVMask, CommonMask)) {
16379 I1 = I2 + CommonMask.
size();
16387 for (
auto [
E, Idx] : SubVectors) {
16388 Type *EScalarTy =
E->Scalars.front()->getType();
16389 bool IsSigned =
true;
16390 if (
auto It =
R.MinBWs.find(
E); It !=
R.MinBWs.end()) {
16393 IsSigned = It->second.second;
16395 if (ScalarTy != EScalarTy) {
16396 unsigned CastOpcode = Instruction::Trunc;
16397 unsigned DstSz =
R.DL->getTypeSizeInBits(ScalarTy);
16398 unsigned SrcSz =
R.DL->getTypeSizeInBits(EScalarTy);
16400 CastOpcode = IsSigned ? Instruction::SExt : Instruction::ZExt;
16401 Cost += TTI.getCastInstrCost(
16411 if (!CommonMask.
empty()) {
16412 std::iota(std::next(CommonMask.
begin(), Idx),
16413 std::next(CommonMask.
begin(), Idx +
E->getVectorFactor()),
16419 if (!ExtMask.
empty()) {
16420 if (CommonMask.
empty()) {
16424 for (
int I = 0, Sz = ExtMask.
size();
I < Sz; ++
I) {
16427 NewMask[
I] = CommonMask[ExtMask[
I]];
16429 CommonMask.
swap(NewMask);
16432 if (CommonMask.
empty()) {
16433 assert(InVectors.
size() == 1 &&
"Expected only one vector with no mask");
16440 createShuffle(InVectors.
front(),
16441 InVectors.
size() == 2 ? InVectors.
back() :
nullptr,
16446 assert((IsFinalized || CommonMask.empty()) &&
16447 "Shuffle construction must be finalized.");
16451const BoUpSLP::TreeEntry *BoUpSLP::getOperandEntry(
const TreeEntry *E,
16452 unsigned Idx)
const {
16453 TreeEntry *
Op = OperandsToTreeEntry.
at({E, Idx});
16454 assert(
Op->isSame(
E->getOperand(Idx)) &&
"Operands mismatch!");
16459 if (
TE.State == TreeEntry::ScatterVectorize ||
16460 TE.State == TreeEntry::StridedVectorize)
16462 if (
TE.State == TreeEntry::CompressVectorize ||
16463 TE.State == TreeEntry::BlendedLoadVectorize)
16465 if (
TE.State == TreeEntry::Vectorize &&
TE.getOpcode() == Instruction::Load &&
16466 !
TE.isAltShuffle()) {
16467 if (
TE.ReorderIndices.empty())
16469 SmallVector<int>
Mask;
16488 if (!L->getExitingBlock())
16495uint64_t BoUpSLP::getScaleToLoopIterations(
const TreeEntry &TE,
Value *Scalar,
16511 if (LI->getLoopFor(
PHI->getParent())) {
16516 if (
PHI->getIncomingValue(
I) != Scalar)
16519 if (!Parent || LI->getLoopDepth(InBB) > LI->getLoopDepth(Parent))
16525 Parent =
U->getParent();
16526 }
else if (
TE.isGather() ||
TE.State == TreeEntry::SplitVectorize) {
16528 while (EI.UserTE) {
16529 if (EI.UserTE->isGather() ||
16530 EI.UserTE->State == TreeEntry::SplitVectorize) {
16531 EI = EI.UserTE->UserTreeIndex;
16534 if (EI.UserTE->State == TreeEntry::Vectorize &&
16535 EI.UserTE->getOpcode() == Instruction::PHI) {
16537 Parent = PH->getIncomingBlock(EI.EdgeIdx);
16539 Parent = EI.UserTE->getMainOp()->
getParent();
16546 Parent =
TE.getMainOp()->getParent();
16548 const Loop *
L = LI->getLoopFor(Parent);
16561 if (
auto It = LoopNestScaleCache.find(L); It != LoopNestScaleCache.end())
16566 SmallVector<const Loop *> Chain;
16567 for (
const Loop *Cur = L; Cur; Cur = Cur->getParentLoop()) {
16568 if (LoopNestScaleCache.contains(Cur))
16572 assert(!Chain.
empty() &&
"Early-return above should have handled cache hit.");
16574 if (
const Loop *Parent = Chain.
back()->getParentLoop())
16575 Scale = LoopNestScaleCache.lookup(Parent);
16582 LoopNestScaleCache.try_emplace(Cur, std::max<uint64_t>(1, Scale));
16584 return std::max<uint64_t>(1, Scale);
16587uint64_t BoUpSLP::getGatherNodeEffectiveScale(
const TreeEntry &TE,
16592 assert((
TE.isGather() ||
TE.State == TreeEntry::SplitVectorize) &&
16593 "Expected gather/split tree entry.");
16595 uint64_t BaseScale = getScaleToLoopIterations(TE,
nullptr, U);
16615 bool Overflow =
false;
16616 for (
Value *V :
TE.Scalars) {
16621 std::min(getScaleToLoopIterations(TE, V, U), BaseScale);
16633 return std::clamp<uint64_t>(Avg, 1, BaseScale);
16636uint64_t BoUpSLP::getEntryEffectiveScale(
const TreeEntry &TE, Instruction *U) {
16637 if (
TE.isGather() ||
TE.State == TreeEntry::SplitVectorize)
16638 return getGatherNodeEffectiveScale(TE, U);
16639 return getScaleToLoopIterations(TE);
16643BoUpSLP::getVectorSpillReloadCost(
const TreeEntry *
E,
Type *ScalarTy,
16653 if (!
E->hasState() ||
E->getOpcode() == Instruction::Store ||
16654 E->getOpcode() == Instruction::ExtractElement ||
16655 E->getOpcode() == Instruction::ExtractValue ||
16656 E->getOpcode() == Instruction::Freeze ||
16657 (
E->getOpcode() == Instruction::Load &&
16658 E->State != TreeEntry::ScatterVectorize))
16659 return SpillsReloads;
16662 E->State == TreeEntry::Vectorize &&
E->getOpcode() == Instruction::PHI;
16663 SmallPtrSet<const TreeEntry *, 8> CountedOpEntries;
16664 SmallDenseMap<unsigned, unsigned> PressureByClass;
16665 auto AddPartsToClass = [&](
unsigned RegClass,
unsigned Parts) {
16666 assert(Parts != 0 &&
"Expected non-zero number of parts (registers).");
16667 PressureByClass[RegClass] += Parts;
16670 auto GetEntryVecTy = [&](
const TreeEntry *
TE) -> std::pair<Type *, Type *> {
16672 auto BWIt = MinBWs.find(TE);
16673 if (BWIt != MinBWs.end()) {
16679 return std::make_pair(ScalarTy,
16683 if (
E->State == TreeEntry::SplitVectorize) {
16684 for (
const auto &[Idx,
_] :
E->CombinedEntriesWithIndices) {
16685 const TreeEntry *OpTE = VectorizableTree[Idx].get();
16687 if (!CountedOpEntries.
insert(OpTE).second)
16689 auto [ScalarTy, OpVecTy] = GetEntryVecTy(OpTE);
16693 const unsigned RC =
16694 TTI->getRegisterClassForType(
true, OpVecTy);
16695 AddPartsToClass(RC, Parts);
16697 }
else if (IsPHI) {
16700 SmallDenseMap<unsigned, unsigned> MaxOpPressureByClass;
16702 const TreeEntry *OpTE = getOperandEntry(
E, Idx);
16703 auto [ScalarTy, OpVecTy] = GetEntryVecTy(OpTE);
16707 const unsigned RC =
16708 TTI->getRegisterClassForType(
true, OpVecTy);
16709 MaxOpPressureByClass[RC] = std::max(MaxOpPressureByClass[RC], Parts);
16711 for (
auto [RC, Parts] : MaxOpPressureByClass)
16712 AddPartsToClass(RC, Parts);
16717 if ((
E->getOpcode() == Instruction::InsertElement ||
16718 E->getOpcode() == Instruction::InsertValue) &&
16727 const TreeEntry *OpTE = getOperandEntry(
E, Idx);
16729 if (!CountedOpEntries.
insert(OpTE).second)
16735 const unsigned RC =
16736 TTI->getRegisterClassForType(
true, OpVecTy);
16737 AddPartsToClass(RC, Parts);
16741 if (
E->getOpcode() != Instruction::Load) {
16743 if (ResParts != 0) {
16744 const unsigned RC = TTI->getRegisterClassForType(
true, VecTy);
16745 AddPartsToClass(RC, ResParts);
16747 if (VecTy != FinalVecTy) {
16749 if (FinalResParts != 0) {
16750 const unsigned RC =
16751 TTI->getRegisterClassForType(
true, FinalVecTy);
16752 AddPartsToClass(RC, FinalResParts);
16757 for (
auto [RegClass, UsedRegs] : PressureByClass) {
16758 const unsigned NumAvailRegs = TTI->getNumberOfRegisters(RegClass);
16759 if (NumAvailRegs == 0 || UsedRegs <= NumAvailRegs)
16761 const unsigned SpillCount = UsedRegs - NumAvailRegs;
16763 TTI->getRegisterClassReloadCost(RegClass, CostKind);
16766 if (
E->Idx > 0 || !UserIgnoreList || !
E->Scalars[0]->getType()->isVoidTy())
16767 SingleRegSpillReload +=
16768 TTI->getRegisterClassSpillCost(RegClass, CostKind);
16769 SpillsReloads += SingleRegSpillReload * SpillCount;
16771 return SpillsReloads;
16779 for (
unsigned I :
seq(VL.
size())) {
16780 if (!DemandedElts[
I])
16801 SmallPtrSetImpl<Value *> &CheckedExtracts) {
16805 if (
SLPReVec &&
E->State == TreeEntry::Vectorize &&
16806 E->getOpcode() == Instruction::InsertElement &&
16807 !
E->getOperand(1).back()->getType()->isVectorTy())
16810 return InstructionCost::getInvalid();
16814 auto It = MinBWs.find(
E);
16815 Type *OrigScalarTy = ScalarTy;
16816 if (It != MinBWs.end()) {
16822 const TreeEntry *ZExt = getOperandEntry(
E, 0);
16826 unsigned EntryVF =
E->getVectorFactor();
16830 getVectorSpillReloadCost(
E, ScalarTy, VecTy, FinalVecTy, CostKind);
16831 if (
E->isGather() || TransformedToGatherNodes.contains(
E)) {
16835 return InstructionCost::getInvalid();
16836 return SpillsReloads +
16837 processBuildVector<ShuffleCostEstimator, InstructionCost>(
16838 E, ScalarTy, *TTI, VectorizedVals, *
this, CheckedExtracts);
16840 if (
E->State == TreeEntry::SplitVectorize) {
16841 assert(
E->CombinedEntriesWithIndices.size() == 2 &&
16842 "Expected exactly 2 combined entries.");
16843 assert(
E->ReuseShuffleIndices.empty() &&
"Expected empty reuses mask.");
16845 if (
E->ReorderIndices.empty()) {
16848 {},
E->CombinedEntriesWithIndices.back().second,
16851 VectorizableTree[
E->CombinedEntriesWithIndices.back().first]
16852 ->getVectorFactor())));
16854 unsigned CommonVF =
16855 std::max(VectorizableTree[
E->CombinedEntriesWithIndices.front().first]
16856 ->getVectorFactor(),
16857 VectorizableTree[
E->CombinedEntriesWithIndices.back().first]
16858 ->getVectorFactor());
16862 CostKind,
E->getSplitMask());
16864 VectorCost += SpillsReloads;
16865 LLVM_DEBUG(dumpTreeCosts(
E, 0, VectorCost, 0,
"Calculated costs for Tree"));
16869 SmallVector<int>
Mask;
16870 if (!
E->ReorderIndices.empty() &&
E->State != TreeEntry::CompressVectorize &&
16871 (
E->State != TreeEntry::StridedVectorize ||
16873 SmallVector<int> NewMask;
16874 if (
E->getOpcode() == Instruction::Store) {
16876 NewMask.
resize(
E->ReorderIndices.size());
16883 if (!
E->ReuseShuffleIndices.empty())
16884 addMask(Mask,
E->ReuseShuffleIndices);
16887 "Expected non-struct vector type for shuffle cost calculation.");
16892 assert((
E->State == TreeEntry::Vectorize ||
16893 E->State == TreeEntry::ScatterVectorize ||
16894 E->State == TreeEntry::StridedVectorize ||
16895 E->State == TreeEntry::ExpandVectorize ||
16896 E->State == TreeEntry::CompressVectorize ||
16897 E->State == TreeEntry::BlendedLoadVectorize) &&
16898 "Unhandled state");
16901 (
E->getOpcode() == Instruction::GetElementPtr &&
16902 E->getMainOp()->getType()->isPointerTy()) ||
16903 E->hasCopyableElements()) &&
16906 unsigned ShuffleOrOp =
16907 E->isAltShuffle() ? (unsigned)Instruction::ShuffleVector :
E->
getOpcode();
16908 if (
E->CombinedOp != TreeEntry::NotCombinedOp)
16909 ShuffleOrOp =
E->CombinedOp;
16910 SmallSetVector<Value *, 16> UniqueValues;
16911 SmallVector<unsigned, 16> UniqueIndexes;
16913 if (UniqueValues.insert(V))
16914 UniqueIndexes.push_back(Idx);
16915 const unsigned Sz = UniqueValues.size();
16916 SmallBitVector UsedScalars(Sz,
false);
16917 for (
unsigned I = 0;
I < Sz; ++
I) {
16919 !
E->isCopyableElement(UniqueValues[
I]) &&
16920 getTreeEntries(UniqueValues[
I]).
front() ==
E)
16922 UsedScalars.set(
I);
16924 auto GetCastContextHint = [&](
Value *
V) {
16926 return getCastContextHint(*OpTEs.front());
16927 InstructionsState SrcState =
getSameOpcode(
E->getOperand(0), *TLI);
16928 if (SrcState && SrcState.
getOpcode() == Instruction::Load &&
16942 ScalarCost = (Sz - UsedScalars.count()) * ScalarEltCost(0);
16944 for (
unsigned I = 0;
I < Sz; ++
I) {
16945 if (UsedScalars.test(
I))
16947 ScalarCost += ScalarEltCost(
I);
16954 if (It != MinBWs.end() && !UnaryInstruction::isCast(
E->getOpcode()) &&
16956 (
E->getOpcode() != Instruction::Load ||
E->UserTreeIndex)) {
16958 if (!EI.UserTE->hasState() ||
16959 EI.UserTE->getOpcode() != Instruction::Select ||
16961 auto UserBWIt = MinBWs.find(EI.UserTE);
16962 Type *UserScalarTy =
16963 (EI.UserTE->isGather() ||
16964 EI.UserTE->State == TreeEntry::SplitVectorize)
16965 ? EI.UserTE->Scalars.front()->getType()
16966 : EI.UserTE->getOperand(EI.EdgeIdx).front()->getType();
16967 if (UserBWIt != MinBWs.end())
16969 UserBWIt->second.first);
16970 if (ScalarTy != UserScalarTy) {
16971 unsigned BWSz = DL->getTypeSizeInBits(ScalarTy);
16972 unsigned SrcBWSz = DL->getTypeSizeInBits(UserScalarTy);
16973 unsigned VecOpcode;
16975 if (BWSz > SrcBWSz)
16976 VecOpcode = Instruction::Trunc;
16979 It->second.second ? Instruction::SExt : Instruction::ZExt;
16981 VecCost += TTI->getCastInstrCost(VecOpcode, UserVecTy, VecTy, CCH,
16986 VecCost += SpillsReloads;
16987 LLVM_DEBUG(dumpTreeCosts(
E, CommonCost, VecCost - CommonCost,
16988 ScalarCost,
"Calculated costs for Tree"));
16989 return VecCost - ScalarCost;
16996 auto GetCostDiffWithPeeled =
17000 for (
Value *V :
E->getReassocScalars()) {
17004 PeeledScalarCost += TTI->getArithmeticInstrCost(
17005 I->getOpcode(), OrigScalarTy, CostKind, Op1Info, Op2Info);
17007 bool PeeledCostAdded =
false;
17009 [&](
unsigned Idx) {
17011 if (!PeeledCostAdded) {
17012 PeeledCostAdded =
true;
17013 Cost += PeeledScalarCost;
17020 if (!PeeledCostAdded)
17021 CostDiff -= PeeledScalarCost;
17027 assert((
E->State == TreeEntry::Vectorize ||
17028 E->State == TreeEntry::StridedVectorize ||
17029 E->State == TreeEntry::ExpandVectorize ||
17030 E->State == TreeEntry::CompressVectorize) &&
17031 "Entry state expected to be Vectorize, StridedVectorize, "
17032 "ExpandVectorize or CompressVectorize here.");
17035 std::tie(ScalarCost, VecCost) =
17036 getGEPCosts(*TTI, Ptrs, BasePtr,
E->getOpcode(), CostKind, OrigScalarTy,
17038 LLVM_DEBUG(dumpTreeCosts(
E, 0, VecCost, ScalarCost,
17039 "Calculated GEPs cost for Tree"));
17041 return VecCost - ScalarCost + SpillsReloads;
17047 return InstructionCost::getInvalid();
17048 Type *CanonicalType = Ty;
17054 IntrinsicCostAttributes CostAttrs(MinMaxID, CanonicalType,
17055 {CanonicalType, CanonicalType});
17057 TTI->getIntrinsicInstrCost(CostAttrs, CostKind);
17060 if (VI && SelectOnly) {
17062 "Expected only for scalar type.");
17065 CI->
getOpcode(), Ty, Builder.getInt1Ty(), CI->getPredicate(),
17066 CostKind, {TTI::OK_AnyValue, TTI::OP_None},
17067 {TTI::OK_AnyValue, TTI::OP_None}, CI);
17071 auto GetFMulAddCost = [&, &TTI = *TTI](
const InstructionsState &S,
17077 switch (ShuffleOrOp) {
17078 case Instruction::PHI: {
17081 SmallPtrSet<const TreeEntry *, 4> CountedOps;
17082 for (
Value *V : UniqueValues) {
17088 for (
unsigned I = 0,
N =
PHI->getNumIncomingValues();
I <
N; ++
I) {
17092 if (
const TreeEntry *OpTE =
17094 if (CountedOps.
insert(OpTE).second &&
17095 !OpTE->ReuseShuffleIndices.empty())
17096 ScalarCost +=
TTI::TCC_Basic * (OpTE->ReuseShuffleIndices.size() -
17097 OpTE->Scalars.size());
17100 return CommonCost - ScalarCost + SpillsReloads;
17102 case Instruction::ExtractValue:
17103 case Instruction::ExtractElement: {
17108 if (ShuffleOrOp == Instruction::ExtractValue && !
E->StructEVIndices.empty())
17110 APInt DemandedElts;
17111 APInt CopyableInsertElts;
17113 auto GetScalarCost = [&](
unsigned Idx) {
17119 if (
E->isCopyableElement(UniqueValues[Idx])) {
17120 if (CopyableInsertElts.
isZero())
17122 CopyableInsertElts.
setBit(Idx);
17128 if (ShuffleOrOp == Instruction::ExtractElement) {
17130 SrcVecTy = EE->getVectorOperandType();
17133 Type *AggregateTy = EV->getAggregateOperand()->getType();
17136 NumElts = ATy->getNumElements();
17142 if (
I->hasOneUse()) {
17152 Cost -= TTI->getCastInstrCost(
17158 if (DemandedElts.
isZero())
17164 return CommonCost +
17165 (CopyableInsertElts.
isZero()
17167 : TTI.getScalarizationOverhead(
17170 CopyableInsertElts,
true,
17171 false, CostKind)) -
17174 : TTI.getScalarizationOverhead(SrcVecTy, DemandedElts,
17178 return GetCostDiff(GetScalarCost, GetVectorCost);
17180 case Instruction::InsertValue:
17181 case Instruction::InsertElement: {
17182 assert(
E->ReuseShuffleIndices.empty() &&
17183 "Unique insertelements only are expected.");
17186 unsigned const NumScalars = VL.
size();
17188 unsigned NumOfParts =
17193 unsigned OffsetEnd = OffsetBeg;
17194 InsertMask[OffsetBeg] = 0;
17197 if (OffsetBeg > Idx)
17199 else if (OffsetEnd < Idx)
17201 InsertMask[Idx] =
I + 1;
17204 if (NumOfParts > 0 && NumOfParts < NumElts)
17205 VecScalarsSz =
PowerOf2Ceil((NumElts + NumOfParts - 1) / NumOfParts);
17206 unsigned VecSz = (1 + OffsetEnd / VecScalarsSz - OffsetBeg / VecScalarsSz) *
17208 unsigned Offset = VecScalarsSz * (OffsetBeg / VecScalarsSz);
17209 unsigned InsertVecSz = std::min<unsigned>(
17211 ((OffsetEnd - OffsetBeg + VecScalarsSz) / VecScalarsSz) * VecScalarsSz);
17212 bool IsWholeSubvector =
17213 OffsetBeg ==
Offset && ((OffsetEnd + 1) % VecScalarsSz == 0);
17217 if (OffsetBeg + InsertVecSz > VecSz) {
17220 InsertVecSz = VecSz;
17225 SmallVector<int>
Mask;
17226 if (!
E->ReorderIndices.empty()) {
17231 std::iota(
Mask.begin(), std::next(
Mask.begin(), InsertVecSz), 0);
17233 bool IsIdentity =
true;
17236 Mask.swap(PrevMask);
17237 for (
unsigned I = 0;
I < NumScalars; ++
I) {
17239 DemandedElts.
setBit(InsertIdx);
17240 AdjustedVL[InsertIdx] = VL[PrevMask[
I]];
17241 IsIdentity &= InsertIdx - OffsetBeg ==
I;
17242 Mask[InsertIdx - OffsetBeg] =
I;
17244 assert(
Offset < NumElts &&
"Failed to find vector index offset");
17254 InsertVecTy, CostKind, Mask);
17256 return !is_contained(E->Scalars, cast<Instruction>(V)->getOperand(0));
17262 SmallBitVector InMask =
17264 buildUseMask(NumElts, InsertMask, UseMask::UndefsAsMask));
17266 *TTI,
SLPReVec, ScalarTy, SrcVecTy, DemandedElts,
17267 true,
false, CostKind, InMask.
all(), AdjustedVL,
17269 if (!InMask.
all() && NumScalars != NumElts && !IsWholeSubvector) {
17270 if (InsertVecSz != VecSz) {
17273 CostKind, {}, OffsetBeg -
Offset, InsertVecTy);
17275 for (
unsigned I = 0, End = OffsetBeg -
Offset;
I < End; ++
I)
17277 for (
unsigned I = OffsetBeg -
Offset, End = OffsetEnd -
Offset;
17281 for (
unsigned I = OffsetEnd + 1 -
Offset;
I < VecSz; ++
I)
17288 if (ShuffleOrOp == Instruction::InsertValue &&
17293 Align VecAlign = std::max(DL->getPrefTypeAlign(SrcVecTy),
17294 DL->getPrefTypeAlign(VL0->
getType()));
17295 Cost += TTI->getMemoryOpCost(Instruction::Store, SrcVecTy, VecAlign,
17297 TTI->getMemoryOpCost(Instruction::Load, VL0->
getType(), VecAlign,
17300 return Cost + SpillsReloads;
17302 case Instruction::ZExt:
17303 case Instruction::SExt:
17304 case Instruction::FPToUI:
17305 case Instruction::FPToSI:
17306 case Instruction::FPExt:
17307 case Instruction::PtrToInt:
17308 case Instruction::PtrToAddr:
17309 case Instruction::IntToPtr:
17310 case Instruction::SIToFP:
17311 case Instruction::UIToFP:
17312 case Instruction::Trunc:
17313 case Instruction::FPTrunc:
17314 case Instruction::BitCast: {
17315 auto SrcIt = MinBWs.find(getOperandEntry(
E, 0));
17318 unsigned Opcode = ShuffleOrOp;
17319 unsigned VecOpcode = Opcode;
17321 (SrcIt != MinBWs.end() || It != MinBWs.end())) {
17323 unsigned SrcBWSz = DL->getTypeSizeInBits(SrcScalarTy->
getScalarType());
17324 if (SrcIt != MinBWs.end()) {
17325 SrcBWSz = SrcIt->second.first;
17331 unsigned BWSz = DL->getTypeSizeInBits(ScalarTy->
getScalarType());
17332 if (BWSz == SrcBWSz) {
17333 VecOpcode = Instruction::BitCast;
17334 }
else if (BWSz < SrcBWSz) {
17335 VecOpcode = Instruction::Trunc;
17336 }
else if (It != MinBWs.end()) {
17337 assert(BWSz > SrcBWSz &&
"Invalid cast!");
17338 VecOpcode = It->second.second ? Instruction::SExt : Instruction::ZExt;
17339 }
else if (SrcIt != MinBWs.end()) {
17340 assert(BWSz > SrcBWSz &&
"Invalid cast!");
17342 SrcIt->second.second ? Instruction::SExt : Instruction::ZExt;
17344 }
else if (VecOpcode == Instruction::SIToFP && SrcIt != MinBWs.end() &&
17345 !SrcIt->second.second) {
17346 VecOpcode = Instruction::UIToFP;
17349 assert(Idx == 0 &&
"Expected 0 index only");
17350 return TTI->getCastInstrCost(Opcode, VL0->
getType(),
17357 if (VecOpcode != Opcode && VecOpcode == Instruction::BitCast)
17359 auto *
VI = VL0->
getOpcode() == Opcode ? VL0 :
nullptr;
17362 bool IsArithmeticExtendedReduction =
17363 E->Idx == 0 && UserIgnoreList &&
17366 return is_contained({Instruction::Add, Instruction::FAdd,
17367 Instruction::Mul, Instruction::FMul,
17368 Instruction::And, Instruction::Or,
17372 if (IsArithmeticExtendedReduction &&
17373 (VecOpcode == Instruction::ZExt || VecOpcode == Instruction::SExt))
17375 return CommonCost +
17376 TTI->getCastInstrCost(VecOpcode, VecTy, SrcVecTy, CCH, CostKind,
17377 VecOpcode == Opcode ? VI :
nullptr);
17379 return GetCostDiff(GetScalarCost, GetVectorCost);
17381 case Instruction::FCmp:
17382 case Instruction::ICmp:
17386 OrigScalarTy = ScalarTy =
17390 case Instruction::Select: {
17391 CmpPredicate VecPred, SwappedVecPred;
17394 match(VL0, MatchCmp))
17400 auto GetScalarCost = [&](
unsigned Idx) {
17415 ShuffleOrOp == Instruction::Select &&
17430 "Expected same type for LHS/RHS");
17433 ScalarCost = TTI->getArithmeticInstrCost(
17435 getOperandInfo(
VI->getOperand(0)), getOperandInfo(
RHS));
17438 ScalarCost = TTI->getArithmeticInstrCost(
17440 getOperandInfo(
VI->getOperand(0)), getOperandInfo(
LHS));
17446 ScalarCost = TTI->getCmpSelInstrCost(
17447 E->getOpcode(), OrigScalarTy,
17450 CurrentPred, CostKind,
17452 VI->getOperand(ShuffleOrOp == Instruction::Select ? 1 : 0)),
17454 VI->getOperand(ShuffleOrOp == Instruction::Select ? 2 : 1)),
17474 if (ShuffleOrOp == Instruction::Select) {
17484 VecCost = TTI->getArithmeticInstrCost(
17485 Instruction::Or, VecTy, CostKind, getOperandInfo(
Cond),
17486 getOperandInfo(
RHS));
17491 VecCost = TTI->getArithmeticInstrCost(
17492 Instruction::And, VecTy, CostKind, getOperandInfo(
Cond),
17493 getOperandInfo(
LHS));
17498 VecCost = TTI->getCmpSelInstrCost(
17499 E->getOpcode(), VecTy, MaskTy, VecPred, CostKind,
17501 E->getOperand(ShuffleOrOp == Instruction::Select ? 1 : 0)),
17503 E->getOperand(ShuffleOrOp == Instruction::Select ? 2 : 1)),
17508 assert(VecTyNumElements >= CondNumElements &&
17509 VecTyNumElements % CondNumElements == 0 &&
17510 "Cannot vectorize Instruction::Select");
17511 if (CondNumElements != VecTyNumElements) {
17521 return VecCost + CommonCost;
17523 return GetCostDiff(GetScalarCost, GetVectorCost);
17525 case TreeEntry::MinMax: {
17526 auto GetScalarCost = [&](
unsigned Idx) {
17527 return GetMinMaxCost(OrigScalarTy);
17531 return VecCost + CommonCost;
17533 return GetCostDiff(GetScalarCost, GetVectorCost);
17535 case TreeEntry::FMulAdd: {
17536 auto GetScalarCost = [&](
unsigned Idx) {
17539 return GetFMulAddCost(
E->getOperations(),
17545 for (
Value *V :
E->Scalars) {
17547 FMF &= FPCI->getFastMathFlags();
17549 FMF &= FPCIOp->getFastMathFlags();
17552 IntrinsicCostAttributes ICA(Intrinsic::fmuladd, VecTy,
17553 {VecTy, VecTy, VecTy}, FMF);
17555 return VecCost + CommonCost;
17557 return GetCostDiff(GetScalarCost, GetVectorCost);
17559 case TreeEntry::ReducedBitcast:
17560 case TreeEntry::ReducedBitcastBSwap: {
17561 auto GetScalarCost = [&, &TTI = *TTI](
unsigned Idx) {
17571 ScalarCost += TTI.getInstructionCost(ZExt, CostKind);
17575 const TreeEntry *LhsTE = getOperandEntry(
E, 0);
17577 getCastContextHint(*getOperandEntry(LhsTE, 0));
17579 auto *SrcVecTy =
getWidenedType(SrcScalarTy, LhsTE->getVectorFactor());
17581 Instruction::BitCast, ScalarTy, SrcVecTy, CastCtx, CostKind);
17582 if (ShuffleOrOp == TreeEntry::ReducedBitcastBSwap) {
17583 auto *SrcType = IntegerType::getIntNTy(
17585 DL->getTypeSizeInBits(SrcScalarTy) * EntryVF);
17586 IntrinsicCostAttributes CostAttrs(Intrinsic::bswap, SrcType, {SrcType});
17588 TTI.getIntrinsicInstrCost(CostAttrs, CostKind);
17590 if (SrcType != ScalarTy) {
17592 TTI.getCastInstrCost(Instruction::ZExt, ScalarTy, SrcType,
17596 return BitcastCost + CommonCost;
17598 return GetCostDiff(GetScalarCost, GetVectorCost);
17600 case TreeEntry::ReducedBitcastLoads:
17601 case TreeEntry::ReducedBitcastBSwapLoads: {
17602 auto GetScalarCost = [&, &TTI = *TTI](
unsigned Idx) {
17612 ScalarCost += TTI.getInstructionCost(ZExt, CostKind);
17616 ScalarCost += TTI.getInstructionCost(
Load, CostKind);
17620 const TreeEntry *LhsTE = getOperandEntry(
E, 0);
17621 const TreeEntry *LoadTE = getOperandEntry(LhsTE, 0);
17623 auto *SrcType = IntegerType::getIntNTy(
17625 DL->getTypeSizeInBits(LI0->getType()) * EntryVF);
17627 TTI.getMemoryOpCost(Instruction::Load, SrcType, LI0->getAlign(),
17628 LI0->getPointerAddressSpace(), CostKind);
17629 if (ShuffleOrOp == TreeEntry::ReducedBitcastBSwapLoads) {
17630 IntrinsicCostAttributes CostAttrs(Intrinsic::bswap, SrcType, {SrcType});
17632 TTI.getIntrinsicInstrCost(CostAttrs, CostKind);
17634 if (SrcType != ScalarTy) {
17636 TTI.getCastInstrCost(Instruction::ZExt, ScalarTy, SrcType,
17640 return LoadCost + CommonCost;
17642 return GetCostDiff(GetScalarCost, GetVectorCost);
17644 case TreeEntry::ReducedCmpBitcast: {
17645 auto GetScalarCost = [&, &TTI = *TTI](
unsigned Idx) {
17657 IntegerType::getIntNTy(ScalarTy->
getContext(),
E->getVectorFactor());
17659 TTI.getCastInstrCost(Instruction::BitCast, DstTy, CmpTy,
17661 if (DstTy != ScalarTy) {
17663 TTI.getCastInstrCost(Instruction::ZExt, ScalarTy, DstTy,
17666 return BitcastCost + CommonCost;
17668 return GetCostDiff(GetScalarCost, GetVectorCost);
17670 case Instruction::FNeg:
17671 case Instruction::Add:
17672 case Instruction::FAdd:
17673 case Instruction::Sub:
17674 case Instruction::FSub:
17675 case Instruction::Mul:
17676 case Instruction::FMul:
17677 case Instruction::UDiv:
17678 case Instruction::SDiv:
17679 case Instruction::FDiv:
17680 case Instruction::URem:
17681 case Instruction::SRem:
17682 case Instruction::FRem:
17683 case Instruction::Shl:
17684 case Instruction::LShr:
17685 case Instruction::AShr:
17686 case Instruction::And:
17687 case Instruction::Or:
17688 case Instruction::Xor: {
17689 auto GetScalarCost = [&](
unsigned Idx) {
17696 unsigned Lane = UniqueIndexes[Idx];
17697 Value *Op1 =
E->getOperand(0)[Lane];
17699 SmallVector<const Value *, 2>
Operands(1, Op1);
17703 Op2 =
E->getOperand(1)[Lane];
17709 ShuffleOrOp, OrigScalarTy, CostKind, Op1Info, Op2Info,
Operands);
17711 I && (ShuffleOrOp == Instruction::FAdd ||
17712 ShuffleOrOp == Instruction::FSub)) {
17721 if (ShuffleOrOp == Instruction::And && It != MinBWs.end() &&
17722 !
E->hasReassocScalars()) {
17727 return CI && CI->getValue().countr_one() >= It->second.first;
17735 *TTI,
SLPReVec, ShuffleOrOp, ScalarTy, VL.
size(), CostKind);
17737 return MaskedCost + CommonCost;
17742 ShuffleOrOp, VecTy, CostKind, Op1Info, Op2Info, {},
nullptr, TLI);
17746 if (
E->hasReassocScalars()) {
17750 return isBinOpIdentityConstant(V, CombineOpcode);
17753 Cost += TTI->getArithmeticInstrCost(
17754 ShuffleOrOp, VecTy, CostKind, {},
17755 getOperandInfo(
E->getOperand(Idx)), {},
nullptr, TLI);
17758 return Cost + CommonCost;
17760 return GetCostDiffWithPeeled(GetScalarCost, GetVectorCost);
17762 case Instruction::GetElementPtr: {
17763 return CommonCost + GetGEPCostDiff(VL, VL0);
17765 case Instruction::Load: {
17766 auto GetScalarCost = [&](
unsigned Idx) {
17768 return TTI->getMemoryOpCost(Instruction::Load, OrigScalarTy,
17769 VI->getAlign(),
VI->getPointerAddressSpace(),
17775 switch (
E->State) {
17776 case TreeEntry::Vectorize:
17777 if (
unsigned Factor =
E->getInterleaveFactor()) {
17778 VecLdCost = TTI->getInterleavedMemoryOpCost(
17779 Instruction::Load, VecTy, Factor, {}, LI0->getAlign(),
17780 LI0->getPointerAddressSpace(), CostKind);
17783 VecLdCost = TTI->getMemoryOpCost(
17784 Instruction::Load, VecTy, LI0->getAlign(),
17788 case TreeEntry::StridedVectorize: {
17790 FixedVectorType *StridedLoadTy = SPtrInfo.
Ty;
17791 assert(StridedLoadTy &&
"Missing StridedPointerInfo for tree entry.");
17792 Align CommonAlignment =
17794 VecLdCost = TTI->getMemIntrinsicInstrCost(
17795 MemIntrinsicCostAttributes(Intrinsic::experimental_vp_strided_load,
17796 StridedLoadTy, LI0->getPointerOperand(),
17797 false, CommonAlignment),
17799 if (StridedLoadTy != VecTy)
17801 TTI->getCastInstrCost(Instruction::BitCast, VecTy, StridedLoadTy,
17802 getCastContextHint(*
E), CostKind);
17806 case TreeEntry::CompressVectorize: {
17808 unsigned InterleaveFactor;
17809 SmallVector<int> CompressMask;
17812 if (!
E->ReorderIndices.empty()) {
17813 SmallVector<int>
Mask(
E->ReorderIndices.begin(),
17814 E->ReorderIndices.end());
17821 Scalars, PointerOps,
E->ReorderIndices, *TTI, *DL, *SE, *AC, *DT,
17822 *TLI, CostKind, [](
Value *) { return true; }, IsMasked,
17823 InterleaveFactor, CompressMask, LoadVecTy);
17824 CompressEntryToData.try_emplace(
E, CompressMask, LoadVecTy,
17825 InterleaveFactor, IsMasked);
17826 Align CommonAlignment = LI0->getAlign();
17827 if (InterleaveFactor) {
17828 VecLdCost = TTI->getInterleavedMemoryOpCost(
17829 Instruction::Load, LoadVecTy, InterleaveFactor, {},
17830 CommonAlignment, LI0->getPointerAddressSpace(), CostKind);
17831 }
else if (IsMasked) {
17832 VecLdCost = TTI->getMemIntrinsicInstrCost(
17833 MemIntrinsicCostAttributes(Intrinsic::masked_load, LoadVecTy,
17835 LI0->getPointerAddressSpace()),
17839 CostKind, CompressMask);
17841 VecLdCost = TTI->getMemoryOpCost(
17842 Instruction::Load, LoadVecTy, CommonAlignment,
17846 CostKind, CompressMask);
17850 case TreeEntry::ScatterVectorize: {
17851 Align CommonAlignment =
17853 VecLdCost = TTI->getMemIntrinsicInstrCost(
17854 MemIntrinsicCostAttributes(Intrinsic::masked_gather, VecTy,
17855 LI0->getPointerOperand(),
17856 false, CommonAlignment),
17860 case TreeEntry::BlendedLoadVectorize: {
17862 Align CommonAlignment =
17865 LI0->getPointerAddressSpace(), CostKind);
17868 case TreeEntry::ExpandVectorize:
17869 case TreeEntry::CombinedVectorize:
17870 case TreeEntry::SplitVectorize:
17871 case TreeEntry::NeedToGather:
17874 return VecLdCost + CommonCost;
17880 if (
E->State == TreeEntry::ScatterVectorize ||
17881 E->State == TreeEntry::BlendedLoadVectorize)
17888 return Cost + GetGEPCostDiff(PointerOps, LI0->getPointerOperand());
17890 case Instruction::Store: {
17891 bool IsReorder = !
E->ReorderIndices.empty();
17892 auto GetScalarCost = [=](
unsigned Idx) {
17895 return TTI->getMemoryOpCost(Instruction::Store, OrigScalarTy,
17896 VI->getAlign(),
VI->getPointerAddressSpace(),
17897 CostKind, OpInfo, VI);
17904 if (
E->State == TreeEntry::StridedVectorize) {
17906 FixedVectorType *StridedStoreTy = SPtrInfo.
Ty;
17907 assert(StridedStoreTy &&
"Missing StridedPointerInfo for tree entry.");
17908 Align CommonAlignment =
17910 VecStCost = TTI->getMemIntrinsicInstrCost(
17911 MemIntrinsicCostAttributes(Intrinsic::experimental_vp_strided_store,
17913 BaseSI->getPointerOperand(),
17914 false, CommonAlignment),
17916 if (StridedStoreTy != VecTy)
17918 TTI->getCastInstrCost(Instruction::BitCast, VecTy, StridedStoreTy,
17919 getCastContextHint(*
E), CostKind);
17920 }
else if (
E->State == TreeEntry::ExpandVectorize) {
17922 FixedVectorType *MaskedStoreTy = SPtrInfo.
Ty;
17923 assert(MaskedStoreTy &&
"Missing StridedPointerInfo for tree entry.");
17924 Align CommonAlignment =
17928 VecStCost = TTI->getMemIntrinsicInstrCost(
17929 MemIntrinsicCostAttributes(Intrinsic::masked_store, MaskedStoreTy,
17931 BaseSI->getPointerAddressSpace()),
17934 assert(
E->State == TreeEntry::Vectorize &&
17935 "Expected either strided, consecutive, or expanded stores.");
17936 if (
unsigned Factor =
E->getInterleaveFactor()) {
17937 assert(
E->ReuseShuffleIndices.empty() && !
E->ReorderIndices.empty() &&
17938 "No reused shuffles expected");
17940 VecStCost = TTI->getInterleavedMemoryOpCost(
17941 Instruction::Store, VecTy, Factor, {}, BaseSI->getAlign(),
17942 BaseSI->getPointerAddressSpace(), CostKind);
17945 VecStCost = TTI->getMemoryOpCost(
17946 Instruction::Store, VecTy, BaseSI->getAlign(),
17947 BaseSI->getPointerAddressSpace(), CostKind, OpInfo);
17950 return VecStCost + CommonCost;
17954 unsigned Idx = IsReorder ?
E->ReorderIndices[
I] :
I;
17958 return GetCostDiff(GetScalarCost, GetVectorCost) +
17959 GetGEPCostDiff(PointerOps, BaseSI->getPointerOperand());
17961 case Instruction::Call: {
17962 auto GetScalarCost = [&](
unsigned Idx) {
17966 E->isCopyableElement(UniqueValues[Idx]))
17971 IntrinsicCostAttributes CostAttrs(ID, *CI, 1);
17972 return TTI->getIntrinsicInstrCost(CostAttrs, CostKind);
17983 It != MinBWs.end() ? It->second.first : 0, TTI);
17984 auto VecCallCosts =
17986 return std::min(VecCallCosts.first, VecCallCosts.second) + CommonCost;
17988 return GetCostDiff(GetScalarCost, GetVectorCost);
17990 case Instruction::ShuffleVector: {
17998 "Invalid Shuffle Vector Operand");
18001 auto TryFindNodeWithEqualOperands = [=]() {
18002 for (
const std::unique_ptr<TreeEntry> &TE : VectorizableTree) {
18005 if (
TE->hasState() &&
TE->isAltShuffle() &&
18006 ((
TE->getOpcode() ==
E->getOpcode() &&
18007 TE->getAltOpcode() ==
E->getAltOpcode()) ||
18008 (
TE->getOpcode() ==
E->getAltOpcode() &&
18009 TE->getAltOpcode() ==
E->getOpcode())) &&
18010 TE->hasEqualOperands(*
E))
18015 auto GetScalarCost = [&](
unsigned Idx) {
18020 assert(
E->getMatchingMainOpOrAltOp(VI) &&
18021 "Unexpected main/alternate opcode");
18023 return TTI->getInstructionCost(VI, CostKind);
18031 if (TryFindNodeWithEqualOperands()) {
18033 dbgs() <<
"SLP: diamond match for alternate node found.\n";
18047 auto ChainCost = [&](
unsigned Opcode) {
18053 Cost += TTIRef.getArithmeticInstrCost(Opcode, VecTy, CostKind,
18054 RunningInfo, ColInfo, {},
18068 VecCost = ChainCost(
E->getOpcode()) + ChainCost(
E->getAltOpcode());
18071 VecCost = TTIRef.getCmpSelInstrCost(
18072 E->getOpcode(), VecTy, MaskTy, CI0->getPredicate(), CostKind,
18073 {TTI::OK_AnyValue, TTI::OP_None}, {TTI::OK_AnyValue, TTI::OP_None},
18075 VecCost += TTIRef.getCmpSelInstrCost(
18076 E->getOpcode(), VecTy, MaskTy,
18078 {TTI::OK_AnyValue, TTI::OP_None}, {TTI::OK_AnyValue, TTI::OP_None},
18081 Type *SrcSclTy =
E->getMainOp()->getOperand(0)->getType();
18084 auto SrcIt = MinBWs.find(getOperandEntry(
E, 0));
18085 unsigned BWSz = DL->getTypeSizeInBits(ScalarTy);
18087 DL->getTypeSizeInBits(
E->getMainOp()->getOperand(0)->getType());
18088 if (SrcIt != MinBWs.end()) {
18089 SrcBWSz = SrcIt->second.first;
18093 if (BWSz <= SrcBWSz) {
18094 if (BWSz < SrcBWSz)
18096 TTIRef.getCastInstrCost(Instruction::Trunc, VecTy, SrcTy,
18100 <<
"SLP: alternate extension, which should be truncated.\n";
18106 VecCost = TTIRef.getCastInstrCost(
E->getOpcode(), VecTy, SrcTy,
18109 TTIRef.getCastInstrCost(
E->getAltOpcode(), VecTy, SrcTy,
18112 SmallVector<int>
Mask;
18113 E->buildAltOpShuffleMask(
18114 [&](Instruction *
I) {
18115 assert(
E->getMatchingMainOpOrAltOp(
I) &&
18116 "Unexpected main/alternate opcode");
18127 if (
E->hasReassocScalars())
18129 unsigned Opcode0 =
E->getOpcode();
18130 unsigned Opcode1 =
E->getAltOpcode();
18131 SmallBitVector OpcodeMask(
18139 return AltVecCost < VecCost ? AltVecCost : VecCost;
18145 return GetCostDiff(
18150 "Not supported shufflevector usage.");
18152 unsigned SVNumElements =
18154 ->getNumElements();
18155 unsigned GroupSize = SVNumElements / SV->getShuffleMask().size();
18156 for (
size_t I = 0, End = VL.
size();
I != End;
I += GroupSize) {
18161 "Not supported shufflevector usage.");
18164 [[maybe_unused]]
bool IsExtractSubvectorMask =
18165 SV->isExtractSubvectorMask(Index);
18166 assert(IsExtractSubvectorMask &&
18167 "Not supported shufflevector usage.");
18168 if (NextIndex != Index)
18170 NextIndex += SV->getShuffleMask().size();
18180 return GetCostDiffWithPeeled(GetScalarCost, GetVectorCost);
18182 case Instruction::Freeze:
18189bool BoUpSLP::isFullyVectorizableTinyTree(
bool ForReduction)
const {
18191 << VectorizableTree.size() <<
" is fully vectorizable .\n");
18193 auto &&AreVectorizableGathers = [
this](
const TreeEntry *
TE,
unsigned Limit) {
18194 SmallVector<int>
Mask;
18195 return TE->isGather() &&
18197 [
this](
Value *V) { return EphValues.contains(V); }) &&
18199 TE->Scalars.size() < Limit ||
18202 (((
TE->hasState() &&
18203 TE->getOpcode() == Instruction::ExtractElement &&
18204 !
TE->hasCopyableElements()) ||
18207 (
TE->hasState() &&
TE->getOpcode() == Instruction::Load &&
18208 !
TE->isAltShuffle()) ||
18213 if (VectorizableTree.size() == 1 &&
18214 (VectorizableTree[0]->State == TreeEntry::Vectorize ||
18215 VectorizableTree[0]->State == TreeEntry::StridedVectorize ||
18216 VectorizableTree[0]->State == TreeEntry::ExpandVectorize ||
18217 VectorizableTree[0]->State == TreeEntry::CompressVectorize ||
18218 VectorizableTree[0]->State == TreeEntry::BlendedLoadVectorize ||
18220 AreVectorizableGathers(VectorizableTree[0].
get(),
18221 VectorizableTree[0]->Scalars.size()) &&
18222 VectorizableTree[0]->getVectorFactor() > 2)))
18225 if (VectorizableTree.size() != 2)
18232 if (VectorizableTree[0]->State == TreeEntry::Vectorize &&
18233 AreVectorizableGathers(VectorizableTree[1].
get(),
18234 VectorizableTree[0]->Scalars.size()))
18238 if (VectorizableTree[0]->
isGather() ||
18239 (VectorizableTree[1]->
isGather() &&
18240 VectorizableTree[0]->State != TreeEntry::ScatterVectorize &&
18241 VectorizableTree[0]->State != TreeEntry::StridedVectorize &&
18242 VectorizableTree[0]->State != TreeEntry::ExpandVectorize &&
18243 VectorizableTree[0]->State != TreeEntry::CompressVectorize &&
18244 VectorizableTree[0]->State != TreeEntry::BlendedLoadVectorize))
18257 if (
SLPReVec && ForReduction && VectorizableTree.size() == 3 &&
18258 VectorizableTree[0]->State == TreeEntry::Vectorize &&
18259 VectorizableTree[0]->getOpcode() == Instruction::ShuffleVector &&
18260 VectorizableTree[1]->isGather() &&
18261 isSplat(VectorizableTree[1]->Scalars) &&
18262 VectorizableTree[2]->
isGather() &&
18264 LLVM_DEBUG(
dbgs() <<
"SLP: Rejecting reduction tree with 3 nodes(shuffle "
18265 "as root and remaining are gather nodes).\n");
18270 if (VectorizableTree.empty()) {
18271 assert(ExternalUses.empty() &&
"We shouldn't have any external users");
18277 if (
any_of(VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &TE) {
18278 return TE->isGather() &&
18282 dbgs() <<
"SLP: rejecting tree with buildvector struct values of size "
18283 << VectorizableTree.size() <<
".\n");
18289 const unsigned TreeSize = VectorizableTree.size();
18291 const bool FrontIsGather = Front.isGather();
18292 const bool FrontHasState = Front.hasState();
18293 const unsigned FrontOpcode = FrontHasState ? Front.getOpcode() : 0u;
18297 constexpr unsigned Limit = 4;
18298 constexpr unsigned LargeTree = 20;
18299 constexpr unsigned LimitTreeSize = 36;
18304 if (!ForReduction) {
18307 if (TreeSize == 1 && FrontIsGather) {
18308 if (FrontHasState && FrontOpcode == Instruction::ExtractElement)
18314 all_of(VectorizableTree, [](
const std::unique_ptr<TreeEntry> &TE) {
18315 return TE->isGather() || TE->State == TreeEntry::SplitVectorize;
18319 FrontOpcode == Instruction::ExtractElement &&
18320 (Front.getVectorFactor() == 2 ||
18324 auto *I = dyn_cast<Instruction>(V);
18325 return !I || !areAllUsersVectorized(I, UserIgnoreList);
18331 VectorizableTree[1]->isGather() &&
18332 (VectorizableTree[1]->getVectorFactor() <= 2 ||
18333 !(
isSplat(VectorizableTree[1]->Scalars) ||
18340 (!ForReduction || Front.getVectorFactor() <= 2) &&
18342 [&](
const std::unique_ptr<TreeEntry> &TE) {
18343 return TE->isGather() && TE->getVectorFactor() <= Limit &&
18353 if (!ForReduction) {
18358 if (TreeSize > 1 && ThresholdNonNegative &&
18359 (!FrontHasState || (FrontOpcode != Instruction::Call &&
18360 FrontOpcode != Instruction::Store)) &&
18362 [](
const std::unique_ptr<TreeEntry> &TE) {
18363 return TE->State == TreeEntry::Vectorize;
18365 all_of(VectorizableTree, [](
const std::unique_ptr<TreeEntry> &TE) {
18366 return TE->State == TreeEntry::Vectorize ||
18367 (TE->isGather() && !
isSplat(TE->Scalars) &&
18377 if (!ThresholdSet &&
18378 all_of(VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &TE) {
18379 const bool IsGather = TE->isGather();
18380 const bool HasState = TE->hasState();
18381 const unsigned Op = HasState ? TE->getOpcode() : 0u;
18382 if (IsGather && (!HasState ||
Op != Instruction::ExtractElement) &&
18383 static_cast<unsigned>(
18386 return HasState &&
Op == Instruction::PHI;
18392 if (ThresholdSet && TreeSize <= Limit) {
18393 bool HasVectorPhi =
false;
18394 auto Compatible = [&](
const std::unique_ptr<TreeEntry> &TE) {
18395 const bool IsGather = TE->isGather();
18396 const bool HasState = TE->hasState();
18397 const unsigned Op = HasState ? TE->getOpcode() : 0u;
18398 if (IsGather && (!HasState ||
Op != Instruction::ExtractElement) &&
18399 static_cast<unsigned>(
18404 if (
Op == Instruction::InsertElement)
18406 if (
Op != Instruction::PHI)
18408 if (TE->State == TreeEntry::Vectorize)
18409 HasVectorPhi =
true;
18411 return isa<PoisonValue>(V) || MustGather.contains(V);
18414 if (
all_of(VectorizableTree, Compatible) && HasVectorPhi)
18419 if (ThresholdNonNegative) {
18420 const bool IsLargeTree = TreeSize >= LargeTree;
18421 bool HasSingleLoad =
false;
18422 if (
all_of(VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &TE) {
18423 const bool IsGather = TE->isGather();
18424 const bool HasState = TE->hasState();
18425 const unsigned Op = HasState ? TE->getOpcode() : 0u;
18429 const bool PrevLoad = HasSingleLoad;
18431 HasState && !IsGather &&
18432 (
Op == Instruction::Load || TE->hasCopyableElements()) &&
18433 (TE->getVectorFactor() > 2 || TE->ReorderIndices.empty());
18435 if (
Op == Instruction::PHI)
18437 if (TE->getVectorFactor() <= Limit &&
18438 (
Op == Instruction::Store ||
18439 (
Op == Instruction::Load && !PrevLoad)))
18442 }
else if (HasState &&
Op == Instruction::PHI) {
18445 return IsGather && (!HasState ||
Op != Instruction::ExtractElement);
18450 if (TreeSize >= 5 && Front.getVectorFactor() <= 2 &&
18451 Front.Scalars.front()->getType()->isIntegerTy()) {
18452 bool VectorNodeFound =
false;
18453 bool AnyNonConst =
false;
18454 if (
all_of(VectorizableTree,
18455 [&](
const std::unique_ptr<TreeEntry> &TE) {
18456 if (TE->State == TreeEntry::Vectorize && TE->hasState()) {
18457 const unsigned Op = TE->getOpcode();
18458 if (
Op == Instruction::PHI ||
18459 !TE->ReorderIndices.empty())
18461 if (VectorNodeFound)
18463 VectorNodeFound =
true;
18470 return TE->isGather() ||
18471 TE->State == TreeEntry::SplitVectorize;
18481 auto IsBenignNode = [&](
const TreeEntry &TE) {
18482 if (TE.State == TreeEntry::SplitVectorize)
18484 const bool IsGather = TE.isGather();
18485 const bool HasState = TE.hasState();
18487 const unsigned Op = TE.getOpcode();
18488 if (
Op == Instruction::PHI)
18490 const unsigned ScalarsSize = TE.Scalars.size();
18491 if (TE.Idx == 0 && ScalarsSize == 2 &&
Op == Instruction::ICmp &&
18492 TreeSize > LimitTreeSize)
18494 if (ScalarsSize == 2 &&
18495 (!TE.ReuseShuffleIndices.empty() || !TE.ReorderIndices.empty() ||
18496 TE.isAltShuffle()))
18498 if (TE.hasCopyableElements() &&
18508 if (!ThresholdSet) {
18510 unsigned NumGathers = 0;
18511 if (
all_of(VectorizableTree,
18512 [&](
const std::unique_ptr<TreeEntry> &TE) {
18513 const bool IsGather = TE->isGather();
18514 if (!IsGather && TE->hasState()) {
18515 const unsigned Op = TE->getOpcode();
18516 if (
Op == Instruction::Load ||
Op == Instruction::Store) {
18523 return IsBenignNode(*TE);
18525 (StoreLoadNodes.
empty() ||
18526 (TreeSize > LimitTreeSize * StoreLoadNodes.
size() &&
18528 none_of(StoreLoadNodes, [&](
const TreeEntry *TE) {
18529 return TE->getOpcode() == Instruction::Store ||
18531 return !isa<LoadInst>(V) ||
18532 areAllUsersVectorized(cast<Instruction>(V));
18540 if (ThresholdNonNegative && TreeSize > LimitTreeSize) {
18541 const TreeEntry *VectorNode =
nullptr;
18542 if (
all_of(VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &TE) {
18543 if (!TE->isGather() && TE->hasState() &&
18544 TE->State != TreeEntry::SplitVectorize &&
18545 TE->getOpcode() != Instruction::PHI) {
18548 VectorNode = TE.get();
18551 return IsBenignNode(*TE);
18558 if (ThresholdSet && TreeSize >= Limit &&
18559 Front.State == TreeEntry::SplitVectorize &&
18561 [](
const std::unique_ptr<TreeEntry> &TE) {
18562 return !TE->isGather() && TE->UserTreeIndex.UserTE &&
18563 TE->UserTreeIndex.UserTE->Idx == 0;
18569 if (ThresholdSet && TreeSize > 2 && Front.State == TreeEntry::Vectorize &&
18570 FrontOpcode == Instruction::InsertElement &&
18571 VectorizableTree[1]->State == TreeEntry::Vectorize &&
18572 VectorizableTree[1]->getOpcode() == Instruction::PHI &&
18574 [](
const std::unique_ptr<TreeEntry> &TE) {
18575 return TE->isGather();
18587 if (isFullyVectorizableTinyTree(ForReduction))
18595 const bool IsAllowedSingleBVNode =
18597 (FrontHasState && !Front.isAltShuffle() && !Front.hasCopyableElements() &&
18598 FrontOpcode != Instruction::PHI &&
18599 FrontOpcode != Instruction::GetElementPtr &&
18601 if (
any_of(VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &TE) {
18602 return TE->isGather() &&
all_of(TE->Scalars, [&](
Value *V) {
18603 return isa<ExtractElementInst, Constant>(V) ||
18604 (IsAllowedSingleBVNode &&
18605 !V->hasNUsesOrMore(UsesLimit) &&
18606 any_of(V->users(), IsaPred<InsertElementInst>));
18611 const TreeEntry &Back = *VectorizableTree.back();
18612 if (Back.isGather() && Back.hasState() && Back.isAltShuffle()) {
18613 const unsigned BackVF = Back.getVectorFactor();
18615 !Back.Scalars.front()->getType()->isVectorTy() &&
18616 TTI->getScalarizationOverhead(
18631 constexpr unsigned SmallTree = 3;
18635 [](
const std::unique_ptr<TreeEntry> &TE) {
18636 return TE->isGather() && TE->hasState() &&
18637 TE->getOpcode() == Instruction::Load &&
18645 TreeEntry &E = *VectorizableTree[Idx];
18646 if (E.State == TreeEntry::SplitVectorize)
18650 if ((E.hasState() && E.getOpcode() != Instruction::Load) ||
18673 if (Root->isGather())
18682 for (
const auto &TEPtr : VectorizableTree) {
18683 if (TEPtr->CombinedOp == TreeEntry::ReducedBitcast ||
18684 TEPtr->CombinedOp == TreeEntry::ReducedBitcastBSwap ||
18685 TEPtr->CombinedOp == TreeEntry::ReducedBitcastLoads ||
18686 TEPtr->CombinedOp == TreeEntry::ReducedBitcastBSwapLoads ||
18687 TEPtr->CombinedOp == TreeEntry::ReducedCmpBitcast) {
18688 ScalarOrPseudoEntries.
insert(TEPtr.get());
18691 if (!TEPtr->isGather()) {
18692 Instruction *LastInst = &getLastInstructionInBundle(TEPtr.get());
18693 EntriesToLastInstruction.
try_emplace(TEPtr.get(), LastInst);
18694 LastInstructions.
insert(LastInst);
18696 if (TEPtr->UserTreeIndex)
18697 EntriesToOperands[TEPtr->UserTreeIndex.UserTE].push_back(TEPtr.get());
18704 auto NoCallIntrinsicOrDoesNotReturn = [
this, &NoCallIntrinsicCache](
18709 if (CB->doesNotReturn())
18714 if (
II->isAssumeLikeIntrinsic())
18716 auto [It, Inserted] = NoCallIntrinsicCache.
try_emplace(
II);
18720 InstructionCost IntrCost = TTI->getIntrinsicInstrCost(ICA, CostKind);
18723 bool Res = IntrCost < CallCost;
18732 CheckedInstructions;
18733 unsigned Budget = 0;
18734 const unsigned BudgetLimit =
18739 "Expected instructions in same block.");
18740 if (
auto It = CheckedInstructions.
find(
Last);
18741 It != CheckedInstructions.
end()) {
18742 const Instruction *Checked = It->second.getPointer();
18743 const bool NoCallsInCachedRange = It->second.getInt() != 0;
18744 if (Checked ==
First)
18745 return NoCallsInCachedRange;
18759 ++
First->getIterator().getReverse(),
18761 Last->getIterator().getReverse();
18763 while (InstIt != PrevInstIt && Budget <= BudgetLimit) {
18768 CB && !NoCallIntrinsicOrDoesNotReturn(CB) && !
isVectorized(CB)) {
18769 for (
const Instruction *LastInst : LastInstsInRange)
18770 CheckedInstructions.
try_emplace(LastInst, &*PrevInstIt, 0);
18773 if (LastInstructions.
contains(&*PrevInstIt))
18774 LastInstsInRange.
push_back(&*PrevInstIt);
18783 const bool Completed = PrevInstIt == InstIt;
18784 const bool NoCallsInRange = Completed || Budget <= BudgetLimit;
18785 for (
const Instruction *LastInst : LastInstsInRange)
18787 LastInst, Completed ?
First : &*PrevInstIt, NoCallsInRange ? 1 : 0);
18788 return NoCallsInRange;
18793 auto GetSpillScale = [&](
const BasicBlock *BB) {
18794 return getLoopNestScale(LI->getLoopFor(BB));
18796 auto AddCosts = [&](
const TreeEntry *
Op, uint64_t Scale) {
18799 Type *ScalarTy =
Op->Scalars.front()->getType();
18800 auto It = MinBWs.find(
Op);
18801 if (It != MinBWs.end())
18804 InstructionCost KeepLiveCost = TTI->getCostOfKeepingLiveOverCall(VecTy);
18805 KeepLiveCost *= Scale;
18806 Cost += KeepLiveCost;
18809 Cost -=
Op->Scalars.size() * TTI->getCostOfKeepingLiveOverCall(ScalarTy) *
18818 ParentOpParentToPreds;
18826 auto BlockHasNoReturnCall = [&](
const BasicBlock *BB) {
18827 auto [It, Inserted] = BlockHasNoReturnCallCache.
try_emplace(BB,
false);
18832 if (CB && CB->doesNotReturn() && !CB->isTerminator()) {
18842 auto LoopBodyHasCall = [&](
const Loop *L) {
18843 if (
auto It = LoopBodyHasNonVecCall.
find(L);
18844 It != LoopBodyHasNonVecCall.
end())
18852 if (BlockHasNoReturnCall(BB))
18856 if (!CB || NoCallIntrinsicOrDoesNotReturn(CB) ||
isVectorized(CB))
18867 auto Key = std::make_pair(Root, OpParent);
18868 if (
auto It = ParentOpParentToPreds.
find(
Key);
18869 It != ParentOpParentToPreds.
end())
18877 const Loop *L = LI->getLoopFor(Root);
18878 const Loop *Outermost =
nullptr;
18879 while (L && !L->contains(OpParent)) {
18881 L = L->getParentLoop();
18883 if (Outermost && LoopBodyHasCall(Outermost)) {
18884 Res = getLoopNestScale(Outermost);
18915 while (!Worklist.
empty()) {
18917 if (BB == OpParent)
18919 if (!Visited.
insert(BB).second)
18924 if (DT->properlyDominates(Root, BB))
18930 if (BlockHasNoReturnCall(BB))
18932 auto Pair = std::make_pair(BB, OpParent);
18933 if (
auto It = ParentOpParentToPreds.
find(Pair);
18934 It != ParentOpParentToPreds.
end()) {
18936 if (It->second == 0)
18946 if (Budget > BudgetLimit)
18954 Res = GetSpillScale(Root);
18958 auto FindNonScalarParentEntry = [&](
const TreeEntry *E) ->
const TreeEntry * {
18960 "Expected scalar or pseudo entry.");
18961 const TreeEntry *Entry = E;
18962 while (Entry->UserTreeIndex) {
18963 Entry = Entry->UserTreeIndex.UserTE;
18964 if (!ScalarOrPseudoEntries.
contains(Entry))
18969 while (!LiveEntries.
empty()) {
18971 const auto OpIt = EntriesToOperands.
find(Entry);
18972 if (OpIt == EntriesToOperands.
end())
18977 if (ScalarOrPseudoEntries.
contains(Entry)) {
18978 Entry = FindNonScalarParentEntry(Entry);
18981 if (!
Op->isGather())
18987 Instruction *LastInst = EntriesToLastInstruction.
at(Entry);
18990 if (!
Op->isGather())
18994 if (Entry->State == TreeEntry::SplitVectorize ||
19001 if (Entry->hasState() && Entry->getOpcode() != Instruction::PHI &&
19003 if (
const Loop *L = LI->getLoopFor(Parent);
19004 L && L->getLoopPreheader() && LoopBodyHasCall(L) &&
19006 return !isa<Instruction>(V) || L->isLoopInvariant(V);
19008 AddCosts(
Op, GetSpillScale(Parent));
19014 Pred = Phi->getIncomingBlock(
Op->UserTreeIndex.EdgeIdx);
19017 if (
Op->isGather()) {
19018 assert(Entry->getOpcode() == Instruction::PHI &&
19019 "Expected phi node only.");
19021 ->getIncomingBlock(
Op->UserTreeIndex.EdgeIdx);
19023 for (
Value *V :
Op->Scalars) {
19034 OpLastInst = EntriesToLastInstruction.
at(
Op);
19038 if (OpParent == Parent) {
19039 if (Entry->getOpcode() == Instruction::PHI) {
19040 if (!CheckForNonVecCallsInSameBlock(LastInst, OpLastInst))
19041 AddCosts(
Op, GetSpillScale(Parent));
19044 if (!CheckForNonVecCallsInSameBlock(OpLastInst, LastInst))
19045 AddCosts(
Op, GetSpillScale(Parent));
19050 if (Entry->getOpcode() != Instruction::PHI &&
19051 !CheckForNonVecCallsInSameBlock(
19053 AddCosts(
Op, GetSpillScale(Parent));
19057 if (!CheckForNonVecCallsInSameBlock(OpLastInst,
19059 AddCosts(
Op, GetSpillScale(OpParent));
19063 if (uint64_t Scale = CheckPredecessors(Parent, Pred, OpParent))
19064 AddCosts(
Op, Scale);
19077 const auto *I1 = IE1;
19078 const auto *I2 = IE2;
19090 if (I1 && (I1 == IE1 || I1->hasOneUse()) &&
19093 if (I2 && ((I2 == IE2 || I2->
hasOneUse())) &&
19096 }
while ((I1 && PrevI1 != I1) || (I2 && PrevI2 != I2));
19103struct ValueSelect {
19104 template <
typename U>
19105 static std::enable_if_t<std::is_same_v<Value *, U>,
Value *>
get(
Value *V) {
19108 template <
typename U>
19109 static std::enable_if_t<!std::is_same_v<Value *, U>,
U>
get(
Value *) {
19127template <
typename T>
19133 assert(!ShuffleMask.empty() &&
"Empty list of shuffles for inserts.");
19135 auto VMIt = std::next(ShuffleMask.begin());
19138 buildUseMask(Mask.size(), Mask, UseMask::UndefsAsMask);
19140 if (!IsBaseUndef.
all()) {
19142 std::pair<T *, bool> Res =
19143 ResizeAction(ShuffleMask.begin()->first, Mask,
false);
19145 for (
unsigned Idx = 0, VF = Mask.size(); Idx < VF; ++Idx) {
19149 Mask[Idx] = (Res.second ? Idx : Mask[Idx]) + VF;
19151 [[maybe_unused]]
auto *V = ValueSelect::get<T *>(
Base);
19152 assert((!V || GetVF(V) == Mask.size()) &&
19153 "Expected base vector of VF number of elements.");
19154 Prev = Action(Mask, {
nullptr, Res.first});
19155 }
else if (ShuffleMask.size() == 1) {
19158 std::pair<T *, bool> Res = ResizeAction(ShuffleMask.begin()->first, Mask,
19164 Prev = Action(Mask, {ShuffleMask.begin()->first});
19168 unsigned Vec1VF = GetVF(ShuffleMask.begin()->first);
19169 unsigned Vec2VF = GetVF(VMIt->first);
19170 if (Vec1VF == Vec2VF) {
19174 for (
unsigned I = 0, VF = Mask.size();
I < VF; ++
I) {
19177 Mask[
I] = SecMask[
I] + Vec1VF;
19180 Prev = Action(Mask, {ShuffleMask.begin()->first, VMIt->first});
19183 std::pair<T *, bool> Res1 = ResizeAction(ShuffleMask.begin()->first, Mask,
19185 std::pair<T *, bool> Res2 =
19186 ResizeAction(VMIt->first, VMIt->second,
false);
19188 for (
unsigned I = 0, VF = Mask.size();
I < VF; ++
I) {
19195 Mask[
I] = (Res2.second ?
I : SecMask[
I]) + VF;
19198 Prev = Action(Mask, {Res1.first, Res2.first});
19200 VMIt = std::next(VMIt);
19202 [[maybe_unused]]
bool IsBaseNotUndef = !IsBaseUndef.
all();
19204 for (
auto E = ShuffleMask.end(); VMIt !=
E; ++VMIt) {
19206 std::pair<T *, bool> Res =
19207 ResizeAction(VMIt->first, VMIt->second,
false);
19209 for (
unsigned I = 0, VF = Mask.size();
I < VF; ++
I) {
19212 "Multiple uses of scalars.");
19213 Mask[
I] = (Res.second ?
I : SecMask[
I]) + VF;
19218 Prev = Action(Mask, {Prev, Res.first});
19227 if (
any_of(VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &TE) {
19228 return TE->isGather() &&
19232 dbgs() <<
"SLP: rejecting tree with buildvector struct values of size "
19233 << VectorizableTree.size() <<
".\n");
19246 if (!Root.hasState() ||
19248 for (
const std::unique_ptr<TreeEntry> &TE : VectorizableTree) {
19249 if (TE->isGather() || TE->Scalars.size() > 2)
19251 for (
Value *V : TE->Scalars)
19253 AnalyzedScalars.insert(V);
19262 << VectorizableTree.size() <<
".\n");
19266 const size_t NumVectScalars = ScalarToTreeEntries.size() + 1;
19268 auto IsExternallyUsedV = [&](
Value *V) {
19269 auto [It, Inserted] = ExternalUseVCache.
try_emplace(V);
19273 if (V->hasOneUse() || V->getType()->isVoidTy()) {
19275 }
else if (V->hasNUsesOrMore(NumVectScalars)) {
19281 m_InsertElt(m_Value(), m_OneUse(m_CastOrSelf(m_Specific(I))),
19284 if (match(U, m_InsertElt(m_Value(), m_Specific(I), m_ConstantInt())))
19286 if (match(U, m_Store(m_OneUse(m_CastOrSelf(m_Specific(I))), m_Value())))
19288 if (match(U, m_Store(m_Specific(I), m_Value())))
19290 ArrayRef<TreeEntry *> Entries = getTreeEntries(U);
19291 if (Entries.empty() && !MustGather.contains(U))
19293 if (any_of(Entries,
19294 [&](TreeEntry *TE) { return DeletedNodes.contains(TE); }))
19296 return any_of(ValueToGatherNodes.lookup(U), [&](
const TreeEntry *TE) {
19297 return DeletedNodes.contains(TE);
19304 auto IsExternallyUsed = [&](
const TreeEntry &TE,
Value *V) {
19305 assert(TE.hasState() && !TE.isGather() &&
19306 TE.State != TreeEntry::SplitVectorize &&
"Expected vector node.");
19307 if (TE.hasCopyableElements() && TE.isCopyableElement(V))
19309 return IsExternallyUsedV(V);
19315 for (
const std::unique_ptr<TreeEntry> &Ptr : VectorizableTree) {
19316 TreeEntry &TE = *Ptr;
19319 if (TE.State == TreeEntry::CombinedVectorize) {
19321 dbgs() <<
"SLP: Skipping cost for combined node that starts with "
19322 << *TE.Scalars[0] <<
".\n";
19323 TE.dump();
dbgs() <<
"SLP: Current total cost = " << Cost <<
"\n");
19324 NodesCosts.try_emplace(&TE);
19327 if (
TE.hasState() &&
19328 (
TE.isGather() ||
TE.State == TreeEntry::SplitVectorize)) {
19329 if (
const TreeEntry *
E =
19330 getSameValuesTreeEntry(
TE.getMainOp(),
TE.Scalars);
19331 E &&
E->getVectorFactor() ==
TE.getVectorFactor()) {
19336 <<
"SLP: Current total cost = " <<
Cost <<
"\n");
19337 NodesCosts.try_emplace(&TE);
19344 assert((!
TE.isGather() ||
TE.Idx == 0 ||
TE.UserTreeIndex) &&
19345 "Expected gather nodes with users only.");
19349 bool CostIsFree =
C == 0;
19354 if (!CostIsFree && !
TE.isGather() &&
TE.hasState()) {
19355 if (PrevVecParent ==
TE.getMainOp()->getParent()) {
19361 if (!CostIsFree && !Scale) {
19362 Scale = getEntryEffectiveScale(TE,
TE.Idx == 0 ? RdxRoot :
nullptr);
19365 if (!
TE.isGather() &&
TE.hasState()) {
19366 PrevVecParent =
TE.getMainOp()->getParent();
19371 NodesCosts.try_emplace(&TE,
C);
19374 <<
"SLP: Current total cost = " <<
Cost <<
"\n");
19376 if (
TE.Idx > 0 && !
TE.UserTreeIndex &&
TE.hasState() &&
19377 TE.getOpcode() == Instruction::Load)
19378 GatheredLoadsNodes.insert(&TE);
19379 if (!
TE.isGather() &&
TE.State != TreeEntry::SplitVectorize &&
19380 !(
TE.Idx == 0 && (
TE.getOpcode() == Instruction::InsertElement ||
19381 TE.getOpcode() == Instruction::InsertValue ||
19382 TE.getOpcode() == Instruction::Store)) &&
19386 for (
Value *V :
TE.Scalars) {
19387 if (IsExternallyUsed(TE, V))
19388 DemandedElts.
setBit(
TE.findLaneForValue(V));
19390 if (!DemandedElts.
isZero()) {
19391 Type *ScalarTy =
TE.Scalars.front()->getType();
19392 auto It = MinBWs.find(&TE);
19393 if (It != MinBWs.end())
19400 if (ExtCost.
isValid() && ExtCost != 0) {
19402 Scale = getScaleToLoopIterations(TE);
19406 ExtractCosts.try_emplace(&TE, ExtCost);
19418 constexpr unsigned PartLimit = 2;
19422 if (
auto It = MinBWs.find(RootTE); It != MinBWs.end()) {
19423 Sz = It->second.first;
19425 Sz = std::max<unsigned>(
19427 DL->getTypeSizeInBits(
19430 const unsigned MinVF =
getMinVF(Sz);
19442 std::tuple<InstructionCost, InstructionCost, SmallVector<unsigned>>>
19443 SubtreeCosts(VectorizableTree.size());
19444 auto UpdateParentNodes =
19445 [&](
const TreeEntry *UserTE,
const TreeEntry *
TE,
19447 SmallDenseSet<std::pair<const TreeEntry *, const TreeEntry *>, 4>
19449 bool AddToList =
true) {
19451 VisitedUser.insert(std::make_pair(TE, UserTE)).second) {
19452 std::get<0>(SubtreeCosts[UserTE->Idx]) += TotalCost;
19453 std::get<1>(SubtreeCosts[UserTE->Idx]) +=
Cost;
19455 std::get<2>(SubtreeCosts[UserTE->Idx]).push_back(
TE->Idx);
19456 UserTE = UserTE->UserTreeIndex.UserTE;
19459 for (
const std::unique_ptr<TreeEntry> &Ptr : VectorizableTree) {
19460 TreeEntry &
TE = *Ptr;
19466 std::get<0>(SubtreeCosts[
TE.Idx]) +=
C + ExtractCost;
19467 std::get<1>(SubtreeCosts[
TE.Idx]) +=
C;
19468 if (
const TreeEntry *UserTE =
TE.UserTreeIndex.UserTE) {
19469 SmallDenseSet<std::pair<const TreeEntry *, const TreeEntry *>, 4>
19471 UpdateParentNodes(UserTE, &TE,
C + ExtractCost,
C, VisitedUser);
19474 SmallDenseSet<std::pair<const TreeEntry *, const TreeEntry *>, 4> Visited;
19475 for (TreeEntry *TE : GatheredLoadsNodes) {
19478 for (
Value *V :
TE->Scalars) {
19479 for (
const TreeEntry *BVTE : ValueToGatherNodes.lookup(V))
19480 UpdateParentNodes(BVTE, TE, TotalCost,
Cost, Visited,
19485 using CostIndicesTy =
19487 SmallVector<unsigned>>>;
19488 struct FirstGreater {
19489 bool operator()(
const CostIndicesTy &
LHS,
const CostIndicesTy &
RHS)
const {
19490 return std::get<0>(
LHS.second) < std::get<0>(
RHS.second) ||
19491 (std::get<0>(
LHS.second) == std::get<0>(
RHS.second) &&
19492 LHS.first->Idx <
RHS.first->Idx);
19495 PriorityQueue<CostIndicesTy, SmallVector<CostIndicesTy>, FirstGreater>
19497 for (
const auto [Idx,
P] :
enumerate(SubtreeCosts)) {
19500 if (VectorizableTree[Idx]->State == TreeEntry::CombinedVectorize)
19502 Worklist.emplace(VectorizableTree[Idx].
get(),
P);
19506 if (!UserIgnoreList &&
getRootNode().getVectorFactor() < MinVF &&
19509 (Worklist.top().first->Idx == 0 || Worklist.top().first->Idx == 1))
19513 bool PreferTrimmedTree =
false;
19514 while (!Worklist.empty() && std::get<0>(Worklist.top().second) > 0) {
19515 TreeEntry *
TE = Worklist.top().first;
19516 if (
TE->isGather() ||
TE->Idx == 0 || DeletedNodes.contains(TE) ||
19520 (
TE->UserTreeIndex &&
19521 TE->UserTreeIndex.UserTE->State == TreeEntry::SplitVectorize &&
19523 ArrayRef<TreeEntry *> Entries = getSplitTreeEntries(V);
19524 return Entries.size() > 1;
19530 if (
TE->State == TreeEntry::Vectorize && !
TE->isAltShuffle() &&
19531 (
TE->getOpcode() == Instruction::ICmp ||
19532 TE->getOpcode() == Instruction::FCmp) &&
19534 auto *I = dyn_cast<CmpInst>(V);
19537 return I->getPredicate() !=
19538 cast<CmpInst>(TE->getMainOp())->getPredicate();
19545 InstructionCost TotalSubtreeCost = std::get<0>(Worklist.top().second);
19547 if (TotalSubtreeCost < TE->Scalars.size()) {
19551 if (!TransformedToGatherNodes.empty()) {
19552 for (
unsigned Idx : std::get<2>(Worklist.top().second)) {
19553 auto It = TransformedToGatherNodes.find(VectorizableTree[Idx].
get());
19554 if (It != TransformedToGatherNodes.end()) {
19555 TotalSubtreeCost -= std::get<0>(SubtreeCosts[Idx]);
19556 SubtreeCost -= std::get<1>(SubtreeCosts[Idx]);
19557 TotalSubtreeCost += It->second;
19558 SubtreeCost += It->second;
19562 if (TotalSubtreeCost < 0 || TotalSubtreeCost < TE->Scalars.size()) {
19566 const unsigned EntryVF =
TE->getVectorFactor();
19570 DemandedElts.
setBit(Idx);
19574 auto It = MinBWs.find(TE);
19575 if (It != MinBWs.end())
19580 true,
false, CostKind);
19581 SmallVector<int>
Mask;
19582 if (!
TE->ReorderIndices.empty() &&
19583 TE->State != TreeEntry::CompressVectorize &&
19584 (
TE->State != TreeEntry::StridedVectorize ||
19586 SmallVector<int> NewMask;
19587 if (
TE->getOpcode() == Instruction::Store) {
19589 NewMask.
resize(
TE->ReorderIndices.size());
19596 if (!
TE->ReuseShuffleIndices.empty())
19597 addMask(Mask,
TE->ReuseShuffleIndices);
19603 if ((!
TE->hasState() || !
TE->isAltShuffle()) &&
19605 return (TE->hasCopyableElements() && TE->isCopyableElement(V)) ||
19606 isConstant(V) || isGathered(V) || getTreeEntries(V).size() > 1;
19610 ArrayRef<unsigned> Nodes = std::get<2>(Worklist.top().second);
19616 auto IsEqualCostAltShuffleToTrim = [&]() {
19617 return TotalSubtreeCost == GatherCost &&
TE->hasState() &&
19619 none_of(Nodes, [&](
unsigned Idx) {
19620 return VectorizableTree[Idx]->hasState() &&
19621 VectorizableTree[Idx]->getOpcode() ==
19622 Instruction::ExtractElement;
19627 bool HasNonPowerOf2 =
any_of(Nodes, [&](
unsigned Idx) {
19631 if (TotalSubtreeCost > GatherCost + TrimMargin ||
19632 IsEqualCostAltShuffleToTrim()) {
19633 PreferTrimmedTree |= TotalSubtreeCost == GatherCost;
19643 <<
" - tree already profitable with cost " <<
Cost
19648 return InstructionCost::getInvalid();
19651 LLVM_DEBUG(
dbgs() <<
"SLP: Trimming unprofitable subtree at node "
19652 <<
TE->Idx <<
" with cost "
19653 << std::get<0>(Worklist.top().second)
19654 <<
" and gather cost " << GatherCost <<
".\n");
19655 if (
TE->UserTreeIndex) {
19656 TransformedToGatherNodes.try_emplace(TE, GatherCost);
19657 NodesCosts.erase(TE);
19659 DeletedNodes.insert(TE);
19660 TransformedToGatherNodes.erase(TE);
19661 NodesCosts.erase(TE);
19663 for (
unsigned Idx : Nodes) {
19664 TreeEntry &ChildTE = *VectorizableTree[Idx];
19665 DeletedNodes.insert(&ChildTE);
19666 TransformedToGatherNodes.erase(&ChildTE);
19667 NodesCosts.erase(&ChildTE);
19677 for (
const TreeEntry *TE : SplatGatheredScalarsRoots)
19678 TotalCost += std::get<1>(SubtreeCosts[
TE->Idx]);
19682 SmallPtrSet<TreeEntry *, 4> SubtreesToDelete;
19683 SmallPtrSet<TreeEntry *, 4> DroppedSplatSubtrees;
19685 using ValuesToInsertTy =
19686 SmallDenseMap<const TreeEntry *, SmallVector<Value *>>;
19687 auto GetScalarTy = [&](
const TreeEntry *
TE) {
19688 Type *ScalarTy =
TE->Scalars.front()->getType();
19689 auto It = MinBWs.find(TE);
19690 if (It != MinBWs.end())
19696 auto FindDemandedElts = [&](TreeEntry *
TE, ValuesToInsertTy &ValuesToInsert) {
19698 for (
Value *V :
TE->Scalars) {
19699 unsigned Pos =
TE->findLaneForValue(V);
19700 for (
const TreeEntry *BVE : ValueToGatherNodes.lookup(V)) {
19701 if (DeletedNodes.contains(BVE))
19703 DemandedElts.
setBit(Pos);
19704 ValuesToInsert.try_emplace(BVE).first->second.push_back(V);
19707 return DemandedElts;
19711 auto GetGatherInsertCost = [&](
Type *ScalarTy,
19712 const ValuesToInsertTy &ValuesToInsert) {
19714 for (
const auto &[BVE,
Values] : ValuesToInsert) {
19719 unsigned Pos = BVE->findLaneForValue(V);
19721 BVDemandedElts.
setBit(Pos);
19726 BVDemandedElts,
true,
false, CostKind,
19736 for (TreeEntry *TE : GatheredLoadsNodes) {
19737 if (DeletedNodes.contains(TE) || TransformedToGatherNodes.contains(TE))
19739 SubtreesToDelete.
insert(TE);
19741 ValuesToInsertTy ValuesToInsert;
19742 APInt DemandedElts = FindDemandedElts(TE, ValuesToInsert);
19743 if (!DemandedElts.
isZero()) {
19744 Type *ScalarTy = GetScalarTy(TE);
19748 false,
true, CostKind);
19749 InstructionCost BVCost = GetGatherInsertCost(ScalarTy, ValuesToInsert);
19750 if (ExtractsCost < BVCost) {
19751 LoadsExtractsCost += ExtractsCost;
19752 SubtreesToDelete.
erase(TE);
19755 LoadsExtractsCost += BVCost;
19757 NodesCosts.erase(TE);
19766 for (TreeEntry *TE : SplatGatheredScalarsRoots) {
19767 if (DeletedNodes.contains(TE))
19769 ValuesToInsertTy ValuesToInsert;
19770 APInt DemandedElts = FindDemandedElts(TE, ValuesToInsert);
19771 if (!DemandedElts.
isZero()) {
19772 Type *ScalarTy = GetScalarTy(TE);
19776 for (
Value *V :
TE->Scalars) {
19781 return none_of(getTreeEntries(U), [&](const TreeEntry *UseTE) {
19782 return !DeletedNodes.contains(UseTE) &&
19783 !TransformedToGatherNodes.contains(UseTE);
19786 ExtractElts.
setBit(
TE->findLaneForValue(V));
19791 ExtractElts,
false,
true, CostKind);
19795 KeepCost += std::get<1>(SubtreeCosts[
TE->Idx]);
19796 InstructionCost DropCost = GetGatherInsertCost(ScalarTy, ValuesToInsert);
19797 if (KeepCost <= DropCost)
19802 DroppedSplatSubtrees.
insert(TE);
19803 for (
unsigned Idx : std::get<2>(SubtreeCosts[
TE->Idx]))
19804 DroppedSplatSubtrees.
insert(VectorizableTree[Idx].
get());
19805 Cost -= std::get<1>(SubtreeCosts[
TE->Idx]);
19808 SubtreesToDelete.
insert(TE);
19809 NodesCosts.erase(TE);
19813 for (std::unique_ptr<TreeEntry> &TE : VectorizableTree) {
19814 if (
TE->UserTreeIndex &&
19815 SubtreesToDelete.
contains(
TE->UserTreeIndex.UserTE)) {
19816 DeletedNodes.insert(
TE.get());
19817 NodesCosts.erase(
TE.get());
19818 SubtreesToDelete.
insert(
TE.get());
19821 DeletedNodes.insert(
TE.get());
19824 for (std::unique_ptr<TreeEntry> &TE : VectorizableTree) {
19825 if (!
TE->UserTreeIndex && TransformedToGatherNodes.contains(
TE.get())) {
19826 assert(
TE->getOpcode() == Instruction::Load &&
"Expected load only.");
19829 if (DeletedNodes.contains(
TE.get()))
19834 if (
TE->isGather() || !NodesCosts.contains(
TE.get())) {
19836 getEntryCost(
TE.get(), VectorizedVals, CheckedExtracts);
19837 if (!
C.isValid() ||
C == 0) {
19838 NodesCosts[
TE.get()] =
C;
19843 Scale = getEntryEffectiveScale(*TE);
19845 NodesCosts[
TE.get()] =
C;
19849 LLVM_DEBUG(
dbgs() <<
"SLP: Recalculate costs after tree trimming.\n");
19851 for (
const auto &
P : NodesCosts) {
19852 NewCost +=
P.second;
19853 LLVM_DEBUG(
dbgs() <<
"SLP: Adding cost " <<
P.second <<
" for bundle "
19856 <<
"SLP: Current total cost = " << NewCost <<
"\n");
19858 if (NewCost + LoadsExtractsCost >
Cost ||
19859 (!PreferTrimmedTree && NewCost + LoadsExtractsCost ==
Cost)) {
19860 DeletedNodes.clear();
19861 TransformedToGatherNodes.clear();
19864 DeletedNodes.insert(DroppedSplatSubtrees.
begin(),
19865 DroppedSplatSubtrees.
end());
19870 if (VectorizableTree.size() >= 2 &&
getRootNode().hasState() &&
19872 TransformedToGatherNodes.contains(VectorizableTree[1].get()))
19873 return InstructionCost::getInvalid();
19874 if (VectorizableTree.size() >= 3 &&
getRootNode().hasState() &&
19876 VectorizableTree[1]->hasState() &&
19877 VectorizableTree[1]->State == TreeEntry::Vectorize &&
19878 (VectorizableTree[1]->
getOpcode() == Instruction::ZExt ||
19879 VectorizableTree[1]->
getOpcode() == Instruction::SExt ||
19880 VectorizableTree[1]->
getOpcode() == Instruction::Trunc) &&
19881 TransformedToGatherNodes.contains(VectorizableTree[2].get()))
19882 return InstructionCost::getInvalid();
19890template <
typename T>
struct ShuffledInsertData {
19894 MapVector<T, SmallVector<int>> ValueMasks;
19908 auto BypassesInstCountCheck = [&]() {
19911 PoorThroughputOpCache Cache;
19912 return any_of(VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &Ptr) {
19913 const TreeEntry &TE = *Ptr;
19914 return TE.hasState() && !DeletedNodes.contains(&TE) && !TE.isGather() &&
19915 !TransformedToGatherNodes.contains(&TE) &&
19916 TE.State != TreeEntry::CombinedVectorize &&
19926 TTI->preferSLPInstCountCheck() &&
getRootNode().getVectorFactor() == 2 &&
19932 const Loop *TreeLoop =
nullptr;
19935 uint64_t NumScalar = getNumScalarInsts(TreeLoop);
19936 uint64_t NumVector = getNumVectorInsts(TreeLoop);
19937 LLVM_DEBUG(
dbgs() <<
"SLP: Inst count check: vector=" << NumVector
19938 <<
" scalar=" << NumScalar <<
"\n");
19939 if (NumVector > NumScalar && !BypassesInstCountCheck()) {
19941 << NumVector <<
" > scalar inst count " << NumScalar
19952 if (!
C.isValid() ||
C == 0)
19955 EntryToScale.
try_emplace(std::make_tuple(&TE, Scalar, U), 0)
19956 .first->getSecond();
19958 Scale = getScaleToLoopIterations(TE, Scalar, U);
19959 LLVM_DEBUG(
dbgs() <<
"Scale " << Scale <<
" For entry " << TE.Idx <<
"\n");
19963 if (UserIgnoreList) {
19965 ReductionCost = ScaleCost(ReductionCost,
getRootNode(),
nullptr,
19970 Cost += ReductionCost;
19972 if (
any_of(ExternalUses, [](
const ExternalUser &EU) {
19974 (EU.E.Idx != 0 || EU.E.State != TreeEntry::Vectorize ||
19975 EU.E.getOpcode() != Instruction::InsertValue) &&
19982 constexpr unsigned CostLimit = 100;
19984 (VectorizableTree.size() - DeletedNodes.size()) *
19990 none_of(ExternalUses, [](
const ExternalUser &EU) {
19996 ExtractCostCalculated;
20002 std::optional<DenseMap<Value *, unsigned>> ValueToExtUses;
20011 for (ExternalUser &EU : ExternalUses)
20012 ScalarUserAndIdx.
emplace_back(EU.Scalar, EU.User, EU.Lane);
20015 bool AllUsersGEPSWithStoresLoads =
true;
20017 Type *UserScalarTy =
nullptr;
20018 for (ExternalUser &EU : ExternalUses) {
20019 Value *Usr = EU.User;
20025 Type *AccessTy =
nullptr;
20030 (!UserScalarTy || UserScalarTy == AccessTy)) {
20031 UserScalarTy = AccessTy;
20034 AllUsersGEPSWithStoresLoads =
false;
20049 for (
const ExternalUser &EU : ExternalUses) {
20052 if (EphValues.count(EU.User))
20055 if (!DT->isReachableFromEntry(UserParent) || UserParent->
isEHPad() ||
20068 if (LI->getLoopFor(
PHI->getParent())) {
20070 if (
PHI->getIncomingValue(Idx) != EU.Scalar)
20074 UseBlock ? DT->findNearestCommonDominator(UseBlock, InBB) : InBB;
20082 auto [It, Inserted] = ScalarToExtractBlock.
try_emplace(EU.Scalar, UseBlock);
20083 if (!Inserted && It->second && UseBlock)
20084 It->second = DT->findNearestCommonDominator(It->second, UseBlock);
20088 for (ExternalUser &EU : ExternalUses) {
20089 LLVM_DEBUG(
dbgs() <<
"SLP: Computing cost for external use of TreeEntry "
20090 << EU.E.Idx <<
" in lane " << EU.Lane <<
"\n");
20092 else dbgs() <<
" User: nullptr\n");
20093 LLVM_DEBUG(
dbgs() <<
" Use: " << EU.Scalar->getNameOrAsOperand() <<
"\n");
20098 if (EphValues.count(EU.User))
20102 if (!CheckedScalarUser.
insert(std::make_pair(EU.Scalar, EU.User)).second ||
20104 CheckedScalarUser.
contains(std::make_pair(EU.Scalar,
nullptr))))
20112 (!DT->isReachableFromEntry(UserParent) || UserParent->isEHPad() ||
20119 (EU.E.hasState() && EU.E.getOpcode() == Instruction::InsertElement)))
20131 if (!UsedInserts.
insert(VU).second)
20135 const TreeEntry *ScalarTE = &EU.E;
20138 [
this, VU](
const ShuffledInsertData<const TreeEntry *> &
Data) {
20143 Value *Op0 =
II->getOperand(0);
20150 if (It == ShuffledInserts.
end()) {
20152 Data.InsertElements.emplace_back(VU);
20154 VecId = ShuffledInserts.
size() - 1;
20155 auto It = MinBWs.find(ScalarTE);
20156 if (It != MinBWs.end() &&
20158 .
insert(std::make_pair(ScalarTE, FTy->getElementType()))
20160 unsigned BWSz = It->second.first;
20161 unsigned DstBWSz = DL->getTypeSizeInBits(FTy->getElementType());
20162 unsigned VecOpcode;
20163 if (DstBWSz < BWSz)
20164 VecOpcode = Instruction::Trunc;
20167 It->second.second ? Instruction::SExt : Instruction::ZExt;
20171 FTy->getNumElements()),
20174 <<
" for extending externally used vector with "
20175 "non-equal minimum bitwidth.\n");
20180 It->InsertElements.front() = VU;
20181 VecId = std::distance(ShuffledInserts.
begin(), It);
20183 int InIdx = *InsertIdx;
20185 ShuffledInserts[VecId].ValueMasks[ScalarTE];
20188 Mask[InIdx] = EU.Lane;
20189 DemandedElts[VecId].setBit(InIdx);
20199 auto *ScalarTy = EU.Scalar->getType();
20200 const unsigned BundleWidth = EU.E.getVectorFactor();
20201 assert(EU.Lane < BundleWidth &&
"Extracted lane out of bounds.");
20203 const TreeEntry *Entry = &EU.E;
20204 auto It = MinBWs.find(Entry);
20207 assert(EU.User &&
"Expected user for struct extract");
20209 Indices.
assign(EV->getIndices());
20212 auto ExtractKey = std::make_pair(EU.Scalar, Indices);
20214 !ExtractCostCalculated.
insert(ExtractKey).second)
20216 if (It != MinBWs.end()) {
20221 ? Instruction::ZExt
20222 : Instruction::SExt;
20228 << ExtraCost <<
"\n");
20230 Type *ExtractTy = VecTy;
20235 *TTI,
SLPReVec, ScalarTy, Instruction::ExtractElement, ExtractTy,
20236 CostKind, EU.Lane, EU.Scalar, ScalarUserAndIdx);
20237 LLVM_DEBUG(
dbgs() <<
" ExtractElement cost for " << *ScalarTy <<
" from "
20238 << *VecTy <<
": " << ExtraCost <<
"\n");
20241 if (Entry->Idx != 0 || Entry->getOpcode() == Instruction::GetElementPtr ||
20242 Entry->getOpcode() == Instruction::Load) {
20244 auto IsPhiInLoop = [&](
const ExternalUser &U) {
20247 const Loop *L = LI->getLoopFor(Phi->getParent());
20248 return L && (Phi->getParent() ==
I->getParent() ||
20249 L == LI->getLoopFor(
I->getParent()));
20253 if (!ValueToExtUses) {
20254 ValueToExtUses.emplace();
20255 for (
const auto &
P :
enumerate(ExternalUses)) {
20257 if (IsPhiInLoop(
P.value()))
20260 ValueToExtUses->try_emplace(
P.value().Scalar,
P.index());
20266 InstructionCost ScalarCost = TTI->getInstructionCost(Inst, CostKind);
20267 auto OperandIsScalar = [&](
Value *V) {
20273 return !EE->hasOneUse() || !MustGather.contains(EE);
20278 return ValueToExtUses->contains(V);
20280 bool CanBeUsedAsScalar =
all_of(Inst->operands(), OperandIsScalar);
20281 bool CanBeUsedAsScalarCast =
false;
20284 Op &&
all_of(
Op->operands(), OperandIsScalar)) {
20287 ? TTI->getInstructionCost(
Op, CostKind)
20289 if (ScalarCost + OpCost <= ExtraCost) {
20290 CanBeUsedAsScalar = CanBeUsedAsScalarCast =
true;
20291 ScalarCost += OpCost;
20295 if (CanBeUsedAsScalar) {
20296 bool KeepScalar = ScalarCost <= ExtraCost;
20300 bool IsProfitablePHIUser =
20308 auto *PHIUser = dyn_cast<PHINode>(U);
20309 return (!PHIUser ||
20310 PHIUser->getParent() !=
20311 getRootNode().getMainOp()->getParent()) &&
20315 return ValueToExtUses->contains(V);
20317 if (IsProfitablePHIUser) {
20321 (!GatheredLoadsEntriesFirst.has_value() ||
20322 Entry->Idx < *GatheredLoadsEntriesFirst)) {
20323 unsigned ScalarUsesCount =
count_if(Entry->Scalars, [&](
Value *V) {
20324 return ValueToExtUses->contains(V);
20326 auto It = ExtractsCount.
find(Entry);
20327 if (It != ExtractsCount.
end()) {
20328 assert(ScalarUsesCount >= It->getSecond().size() &&
20329 "Expected total number of external uses not less than "
20330 "number of scalar uses.");
20331 ScalarUsesCount -= It->getSecond().size();
20336 KeepScalar = ScalarUsesCount <= 1 || !
has_single_bit(ScalarUsesCount);
20339 ExternalUsesAsOriginalScalar.insert(EU.Scalar);
20340 for (
Value *V : Inst->operands()) {
20346 auto It = ValueToExtUses->find(V);
20347 if (It != ValueToExtUses->end()) {
20349 ExternalUses[It->second].User =
nullptr;
20352 ExtraCost = ScalarCost;
20353 if (!IsPhiInLoop(EU))
20354 ExtractsCount[Entry].
insert(Inst);
20355 if (CanBeUsedAsScalarCast) {
20356 ScalarOpsFromCasts.
insert(Inst->getOperand(0));
20360 for (
Value *V : IOp->operands()) {
20363 auto It = ValueToExtUses->find(V);
20364 if (It != ValueToExtUses->end()) {
20366 ExternalUses[It->second].User =
nullptr;
20381 if (!ExternalUsesAsOriginalScalar.contains(EU.Scalar)) {
20382 if (ExtraCost.
isValid() && ExtraCost != 0) {
20392 ExtraCost = ScaleCost(ExtraCost, *Entry, EU.Scalar,
nullptr);
20395 if (
const Loop *L = ExtractBB ? LI->getLoopFor(ExtractBB) :
nullptr) {
20396 uint64_t Scale = getLoopNestScale(
20399 <<
"SLP: Extract scale " << Scale <<
" (NCD block) for "
20400 << EU.Scalar->getNameOrAsOperand() <<
"\n");
20401 ExtraCost *= Scale;
20406 ExtraCost = ScaleCost(ExtraCost, *Entry, EU.Scalar,
20410 ExtractCost += ExtraCost;
20418 if (AllUsersGEPSWithStoresLoads && !Pointers.
empty()) {
20424 auto *VecTy =
getWidenedType(UserScalarTy, RootEntry.Scalars.size());
20426 Pointers, CommonBase, TTI::PointersChainInfo::getUnitStride(),
20427 UserScalarTy, CostKind);
20429 Pointers, CommonBase, TTI::PointersChainInfo::getUnknownStride(),
20431 ExtractCost += ScaleCost(VectorGEPCost - ScalarGEPCost, RootEntry);
20436 for (
Value *V : ScalarOpsFromCasts) {
20437 ExternalUsesAsOriginalScalar.insert(V);
20439 const auto *It =
find_if_not(TEs, [&](TreeEntry *TE) {
20440 return TransformedToGatherNodes.contains(TE) ||
20441 DeletedNodes.contains(TE);
20443 if (It != TEs.end()) {
20444 const TreeEntry *UserTE = *It;
20445 ExternalUses.emplace_back(V,
nullptr, *UserTE,
20446 UserTE->findLaneForValue(V));
20451 if (!VectorizedVals.
empty()) {
20453 auto BWIt = MinBWs.find(&Root);
20454 if (BWIt != MinBWs.end()) {
20455 Type *DstTy = Root.Scalars.front()->getType();
20456 unsigned OriginalSz = DL->getTypeSizeInBits(DstTy->
getScalarType());
20458 ReductionBitWidth == 0 ? BWIt->second.first : ReductionBitWidth;
20459 if (OriginalSz != SrcSz) {
20460 unsigned Opcode = Instruction::Trunc;
20461 if (OriginalSz > SrcSz)
20462 Opcode = BWIt->second.second ? Instruction::SExt : Instruction::ZExt;
20470 CastCost = ScaleCost(CastCost, Root,
nullptr, ReductionRoot);
20480 VectorizableTree[1]->hasState() &&
20481 VectorizableTree[1]->State == TreeEntry::Vectorize &&
20482 all_of(VectorizableTree[1]->Scalars, [&](
Value *V) {
20483 return ExternalUsesAsOriginalScalar.contains(V);
20487 Cost += ExtractCost;
20488 auto &&ResizeToVF = [
this, &Cost](
const TreeEntry *TE,
ArrayRef<int> Mask,
20489 bool ForSingleMask) {
20491 unsigned VF = Mask.size();
20492 unsigned VecVF = TE->getVectorFactor();
20493 bool HasLargeIndex =
20494 any_of(Mask, [VF](
int Idx) {
return Idx >=
static_cast<int>(VF); });
20495 if ((VF != VecVF && HasLargeIndex) ||
20498 if (HasLargeIndex) {
20500 std::copy(Mask.begin(), std::next(Mask.begin(), std::min(VF, VecVF)),
20505 CostKind, OrigMask);
20507 dbgs() <<
"SLP: Adding cost " <<
C
20508 <<
" for final shuffle of insertelement external users.\n";
20509 TE->dump();
dbgs() <<
"SLP: Current total cost = " << Cost <<
"\n");
20511 return std::make_pair(TE,
true);
20514 if (!ForSingleMask) {
20516 for (
unsigned I = 0;
I < VF; ++
I) {
20518 ResizeMask[Mask[
I]] = Mask[
I];
20523 TE->getMainOp()->getType(), VecVF)),
20524 CostKind, ResizeMask);
20526 dbgs() <<
"SLP: Adding cost " <<
C
20527 <<
" for final shuffle of insertelement external users.\n";
20528 TE->dump();
dbgs() <<
"SLP: Current total cost = " << Cost <<
"\n");
20533 return std::make_pair(TE,
false);
20536 for (
int I = 0, E = ShuffledInserts.
size();
I < E; ++
I) {
20537 Value *
Base = ShuffledInserts[
I].InsertElements.
front()->getOperand(0);
20538 auto Vector = ShuffledInserts[
I].ValueMasks.takeVector();
20542 assert((TEs.size() == 1 || TEs.size() == 2) &&
20543 "Expected exactly 1 or 2 tree entries.");
20544 if (TEs.size() == 1) {
20546 VF = TEs.front()->getVectorFactor();
20547 auto *FTy =
getWidenedType(TEs.back()->Scalars.front()->getType(), VF);
20551 (
Data.index() < VF &&
20552 static_cast<int>(
Data.index()) ==
Data.value());
20557 C = ScaleCost(
C, *TEs.front());
20559 <<
" for final shuffle of insertelement "
20560 "external users.\n";
20561 TEs.front()->
dump();
20562 dbgs() <<
"SLP: Current total cost = " << Cost <<
"\n");
20568 TEs.front()->getVectorFactor() == TEs.back()->getVectorFactor())
20569 VF = TEs.front()->getVectorFactor();
20573 auto *FTy =
getWidenedType(TEs.back()->Scalars.front()->getType(), VF);
20576 C = ScaleCost(
C, *TEs.back());
20578 <<
" for final shuffle of vector node and external "
20579 "insertelement users.\n";
20580 if (TEs.front()) { TEs.front()->dump(); } TEs.back()->dump();
20581 dbgs() <<
"SLP: Current total cost = " << Cost <<
"\n");
20589 [](
const TreeEntry *E) { return E->getVectorFactor(); }, ResizeToVF,
20590 EstimateShufflesCost);
20593 ShuffledInserts[
I].InsertElements.
front()->getType()),
20595 true,
false, CostKind);
20596 Cost -= InsertCost;
20600 if (ReductionBitWidth != 0) {
20601 assert(UserIgnoreList &&
"Expected reduction tree.");
20603 auto It = MinBWs.find(&E);
20604 if (It != MinBWs.end() && It->second.first != ReductionBitWidth) {
20605 unsigned SrcSize = It->second.first;
20606 unsigned DstSize = ReductionBitWidth;
20607 unsigned Opcode = Instruction::Trunc;
20608 if (SrcSize < DstSize) {
20609 bool IsArithmeticExtendedReduction =
20612 return is_contained({Instruction::Add, Instruction::FAdd,
20613 Instruction::Mul, Instruction::FMul,
20614 Instruction::And, Instruction::Or,
20618 if (IsArithmeticExtendedReduction)
20620 Instruction::BitCast;
20622 Opcode = It->second.second ? Instruction::SExt : Instruction::ZExt;
20624 if (Opcode != Instruction::BitCast) {
20626 getWidenedType(Builder.getIntNTy(SrcSize), E.getVectorFactor());
20628 getWidenedType(Builder.getIntNTy(DstSize), E.getVectorFactor());
20630 switch (E.getOpcode()) {
20631 case Instruction::SExt:
20632 case Instruction::ZExt:
20633 case Instruction::Trunc: {
20634 const TreeEntry *OpTE = getOperandEntry(&E, 0);
20635 CCH = getCastContextHint(*OpTE);
20642 TTI->getCastInstrCost(Opcode, DstVecTy, SrcVecTy, CCH, CostKind);
20643 CastCost = ScaleCost(CastCost,
getRootNode(),
nullptr,
20647 <<
" for final resize for reduction from " << SrcVecTy
20648 <<
" to " << DstVecTy <<
"\n";
20649 dbgs() <<
"SLP: Current total cost = " << Cost <<
"\n");
20654 std::optional<InstructionCost> SpillCost;
20657 Cost += *SpillCost;
20663 OS <<
"SLP: Spill Cost = ";
20668 OS <<
".\nSLP: Extract Cost = " << ExtractCost <<
".\n";
20670 OS <<
"SLP: Reduction Cost = " << ReductionCost <<
".\n";
20671 OS <<
"SLP: Total Cost = " << Cost <<
".\n";
20675 ViewGraph(
this,
"SLP" + F->getName(),
false, Str);
20686std::optional<TTI::ShuffleKind>
20687BoUpSLP::tryToGatherSingleRegisterExtractElements(
20693 for (
int I = 0, E = VL.
size();
I < E; ++
I) {
20709 if (Idx >= VecTy->getNumElements()) {
20713 SmallBitVector ExtractMask(VecTy->getNumElements(),
true);
20714 ExtractMask.reset(*Idx);
20721 VectorOpToIdx[EI->getVectorOperand()].push_back(
I);
20726 stable_sort(Vectors, [](
const auto &P1,
const auto &P2) {
20727 return P1.second.size() >
P2.second.size();
20730 const int UndefSz = UndefVectorExtracts.
size();
20731 unsigned SingleMax = 0;
20732 unsigned PairMax = 0;
20733 if (!Vectors.
empty()) {
20734 SingleMax = Vectors.
front().second.size() + UndefSz;
20735 if (Vectors.
size() > 1) {
20736 auto *ItNext = std::next(Vectors.
begin());
20737 PairMax = SingleMax + ItNext->second.size();
20740 if (SingleMax == 0 && PairMax == 0 && UndefSz == 0)
20741 return std::nullopt;
20747 if (SingleMax >= PairMax && SingleMax) {
20748 for (
int Idx : Vectors.
front().second)
20749 std::swap(GatheredExtracts[Idx], VL[Idx]);
20750 }
else if (!Vectors.
empty()) {
20751 for (
unsigned Idx : {0, 1})
20752 for (
int Idx : Vectors[Idx].second)
20753 std::swap(GatheredExtracts[Idx], VL[Idx]);
20756 for (
int Idx : UndefVectorExtracts)
20757 std::swap(GatheredExtracts[Idx], VL[Idx]);
20760 std::optional<TTI::ShuffleKind> Res =
20766 return std::nullopt;
20770 for (
int I = 0,
E = GatheredExtracts.size();
I <
E; ++
I) {
20791BoUpSLP::tryToGatherExtractElements(SmallVectorImpl<Value *> &VL,
20792 SmallVectorImpl<int> &Mask,
20793 unsigned NumParts)
const {
20794 assert(NumParts > 0 &&
"NumParts expected be greater than or equal to 1.");
20801 const unsigned PartOffset = Part * SliceSize;
20804 if (PartOffset + PartSize > VL.
size())
20808 SmallVector<int> SubMask;
20809 std::optional<TTI::ShuffleKind> Res =
20810 tryToGatherSingleRegisterExtractElements(SubVL, SubMask);
20811 ShufflesRes[Part] = Res;
20812 copy(SubMask, std::next(
Mask.begin(), Part * SliceSize));
20813 if (SubVL.
size() != SliceSize)
20816 if (
none_of(ShufflesRes, [](
const std::optional<TTI::ShuffleKind> &Res) {
20817 return Res.has_value();
20819 ShufflesRes.clear();
20820 return ShufflesRes;
20823std::optional<TargetTransformInfo::ShuffleKind>
20824BoUpSLP::isGatherShuffledSingleRegisterEntry(
20826 SmallVectorImpl<const TreeEntry *> &Entries,
unsigned Part,
bool ForOrder,
20827 unsigned SliceSize) {
20830 return std::nullopt;
20831 const unsigned MaskBase = Part * SliceSize;
20834 auto GetUserEntry = [&](
const TreeEntry *
TE) {
20835 while (
TE->UserTreeIndex &&
TE->UserTreeIndex.EdgeIdx == UINT_MAX)
20836 TE =
TE->UserTreeIndex.UserTE;
20838 return EdgeInfo(
const_cast<TreeEntry *
>(TE), 0);
20839 return TE->UserTreeIndex;
20841 auto HasGatherUser = [&](
const TreeEntry *
TE) {
20842 while (
TE->Idx != 0 &&
TE->UserTreeIndex) {
20843 if (
TE->UserTreeIndex.EdgeIdx == UINT_MAX)
20845 TE =
TE->UserTreeIndex.UserTE;
20849 const EdgeInfo TEUseEI = GetUserEntry(TE);
20850 if (!TEUseEI || (TEUseEI.UserTE->Idx == 0 && TEUseEI.UserTE->isGather() &&
20851 !TEUseEI.UserTE->hasState()))
20852 return std::nullopt;
20853 const Instruction *TEInsertPt = &getLastInstructionInBundle(TEUseEI.UserTE);
20858 TEUseEI.UserTE->hasState() ? TEUseEI.UserTE->getMainOp() :
nullptr);
20859 PHI && TEUseEI.UserTE->State != TreeEntry::SplitVectorize) {
20860 TEInsertBlock =
PHI->getIncomingBlock(TEUseEI.EdgeIdx);
20863 TEInsertBlock = TEInsertPt->
getParent();
20865 if (!DT->isReachableFromEntry(TEInsertBlock))
20866 return std::nullopt;
20867 auto *NodeUI = DT->getNode(TEInsertBlock);
20868 assert(NodeUI &&
"Should only process reachable instructions");
20870 auto CheckOrdering = [&](
const Instruction *InsertPt) {
20883 const BasicBlock *InsertBlock = InsertPt->getParent();
20884 auto *NodeEUI = DT->getNode(InsertBlock);
20887 assert((NodeUI == NodeEUI) ==
20888 (NodeUI->getDFSNumIn() == NodeEUI->getDFSNumIn()) &&
20889 "Different nodes should have different DFS numbers");
20891 if (TEInsertPt->
getParent() != InsertBlock &&
20892 (DT->dominates(NodeUI, NodeEUI) || !DT->dominates(NodeEUI, NodeUI)))
20894 if (TEInsertPt->
getParent() == InsertBlock &&
20907 SmallDenseMap<Value *, int> UsedValuesEntry;
20908 SmallPtrSet<const Value *, 16> VisitedValue;
20909 bool IsReusedNodeFound =
false;
20910 auto CheckAndUseSameNode = [&](
const TreeEntry *TEPtr) {
20912 if (IsReusedNodeFound)
20914 if ((TEPtr->getVectorFactor() != VL.
size() &&
20915 TEPtr->Scalars.size() != VL.
size()) ||
20916 (!TEPtr->isSame(VL) && !TEPtr->isSame(
TE->Scalars)))
20918 IsReusedNodeFound =
20919 equal(
TE->Scalars, TEPtr->Scalars) &&
20920 equal(
TE->ReorderIndices, TEPtr->ReorderIndices) &&
20921 equal(
TE->ReuseShuffleIndices, TEPtr->ReuseShuffleIndices);
20924 for (
Value *V : VL) {
20931 auto CheckParentNodes = [&](
const TreeEntry *User1,
const TreeEntry *User2,
20932 unsigned EdgeIdx) {
20933 const TreeEntry *Ptr1 = User1;
20934 const TreeEntry *Ptr2 = User2;
20935 SmallDenseMap<const TreeEntry *, unsigned> PtrToIdx;
20938 EdgeIdx = Ptr2->UserTreeIndex.EdgeIdx;
20939 Ptr2 = Ptr2->UserTreeIndex.UserTE;
20942 unsigned Idx = Ptr1->UserTreeIndex.EdgeIdx;
20943 Ptr1 = Ptr1->UserTreeIndex.UserTE;
20944 if (
auto It = PtrToIdx.
find(Ptr1); It != PtrToIdx.
end())
20945 return Idx < It->second;
20951 std::optional<bool> TEInsertPtUsedOutsideBlock;
20952 auto IsTEInsertPtUsedOutsideBlock = [&] {
20953 if (!TEInsertPtUsedOutsideBlock)
20954 TEInsertPtUsedOutsideBlock =
20956 return *TEInsertPtUsedOutsideBlock;
20961 const bool TEUseEIInsertPtUsedOutside =
20962 TEUseEI && TEUseEI.UserTE && TEUseEI.UserTE->hasCopyableElements() &&
20963 !TEUseEI.UserTE->isCopyableElement(
20965 IsTEInsertPtUsedOutsideBlock();
20966 auto CheckNonSchedulableOrdering = [&](
const TreeEntry *
E,
20968 return TEUseEIInsertPtUsedOutside &&
20969 InsertPt->getNextNode() == TEInsertPt &&
20970 (!
E->hasCopyableElements() || !
E->isCopyableElement(InsertPt) ||
20976 const bool TEUserNeedsEmitFirst =
20977 TEUseEI.UserTE->State == TreeEntry::Vectorize &&
20978 TEUseEI.UserTE->hasState() &&
20979 (TEUseEI.UserTE->getOpcode() != Instruction::PHI ||
20980 TEUseEI.UserTE->isAltShuffle()) &&
20984 SmallDenseMap<const TreeEntry *, bool> ScalarsUsedOutsideBlockCache;
20985 auto AllScalarsUsedOutsideBlock = [&](
const TreeEntry *UserTE) {
20993 for (
Value *V : VL) {
20997 SmallPtrSet<const TreeEntry *, 4> VToTEs;
20999 ValueToGatherNodes.lookup(V).takeVector());
21000 if (TransformedToGatherNodes.contains(TE)) {
21001 for (TreeEntry *
E : getSplitTreeEntries(V)) {
21002 if (TE ==
E || !TransformedToGatherNodes.contains(
E) ||
21003 !
E->UserTreeIndex ||
E->UserTreeIndex.UserTE->isGather())
21005 GatherNodes.push_back(
E);
21007 for (TreeEntry *
E : getTreeEntries(V)) {
21008 if (TE ==
E || !TransformedToGatherNodes.contains(
E) ||
21009 !
E->UserTreeIndex ||
E->UserTreeIndex.UserTE->isGather())
21011 GatherNodes.push_back(
E);
21014 for (
const TreeEntry *TEPtr : GatherNodes) {
21015 if (TEPtr == TE || TEPtr->Idx == 0 || DeletedNodes.contains(TEPtr))
21018 [&](
Value *V) { return GatheredScalars.contains(V); }) &&
21019 "Must contain at least single gathered value.");
21020 assert(TEPtr->UserTreeIndex &&
21021 "Expected only single user of a gather node.");
21022 if (
any_of(TEPtr->CombinedEntriesWithIndices,
21023 [&](
const auto &
P) { return P.first == TE->Idx; }))
21025 const EdgeInfo &UseEI = TEPtr->UserTreeIndex;
21027 PHINode *UserPHI = (UseEI.UserTE->State != TreeEntry::SplitVectorize &&
21028 UseEI.UserTE->hasState())
21033 : &getLastInstructionInBundle(UseEI.UserTE);
21034 if (TEInsertPt == InsertPt) {
21036 if (TEUserNeedsEmitFirst) {
21037 if (UseEI.UserTE->State != TreeEntry::Vectorize ||
21038 (UseEI.UserTE->hasState() &&
21039 UseEI.UserTE->getOpcode() == Instruction::PHI &&
21040 !UseEI.UserTE->isAltShuffle()) ||
21041 !AllScalarsUsedOutsideBlock(UseEI.UserTE))
21049 (TEUseEI.UserTE != UseEI.UserTE || TEUseEI.EdgeIdx < UseEI.EdgeIdx))
21052 if (TEUseEI.UserTE->State == TreeEntry::Vectorize &&
21053 TEUseEI.UserTE->getOpcode() == Instruction::PHI &&
21054 UseEI.UserTE->State == TreeEntry::Vectorize &&
21055 UseEI.UserTE->getOpcode() == Instruction::PHI &&
21056 TEUseEI.UserTE != UseEI.UserTE)
21061 if (TEUseEI.UserTE == UseEI.UserTE && TEUseEI.EdgeIdx < UseEI.EdgeIdx)
21065 if (TEUseEI.UserTE != UseEI.UserTE &&
21066 (TEUseEI.UserTE->Idx < UseEI.UserTE->Idx ||
21067 HasGatherUser(TEUseEI.UserTE)))
21070 if (CheckParentNodes(TEUseEI.UserTE, UseEI.UserTE, UseEI.EdgeIdx))
21074 if (!TEUseEI.UserTE->isGather() && !UserPHI &&
21075 TEUseEI.UserTE->doesNotNeedToSchedule() !=
21076 UseEI.UserTE->doesNotNeedToSchedule() &&
21081 if ((TEInsertBlock != InsertPt->
getParent() ||
21082 TEUseEI.EdgeIdx < UseEI.EdgeIdx || TEUseEI.UserTE != UseEI.UserTE) &&
21083 (!CheckOrdering(InsertPt) ||
21084 (UseEI.UserTE->hasCopyableElements() &&
21085 IsTEInsertPtUsedOutsideBlock() &&
21089 if (CheckAndUseSameNode(TEPtr))
21094 if (CheckNonSchedulableOrdering(UseEI.UserTE, InsertPt))
21099 const auto *It =
find_if(VTEs, [&](
const TreeEntry *MTE) {
21100 return MTE !=
TE && MTE != TEUseEI.UserTE &&
21101 !DeletedNodes.contains(MTE) &&
21102 !TransformedToGatherNodes.contains(MTE);
21104 if (It != VTEs.end()) {
21105 const TreeEntry *VTE = *It;
21106 if (
none_of(
TE->CombinedEntriesWithIndices,
21107 [&](
const auto &
P) { return P.first == VTE->Idx; })) {
21108 Instruction &LastBundleInst = getLastInstructionInBundle(VTE);
21109 if (&LastBundleInst == TEInsertPt || !CheckOrdering(&LastBundleInst))
21113 if (CheckAndUseSameNode(VTE))
21119 const auto *It =
find_if(VTEs, [&, MainTE = TE](
const TreeEntry *TE) {
21120 return TE != MainTE && !DeletedNodes.contains(TE) &&
21121 !TransformedToGatherNodes.contains(TE);
21123 if (It != VTEs.end()) {
21124 const TreeEntry *VTE = *It;
21125 if (ForOrder && VTE->Idx < GatheredLoadsEntriesFirst.value_or(0) &&
21126 VTEs.size() > 1 && VTE->State != TreeEntry::Vectorize) {
21127 VTEs = VTEs.drop_front();
21129 const auto *MIt =
find_if(VTEs, [](
const TreeEntry *MTE) {
21130 return MTE->State == TreeEntry::Vectorize;
21132 if (MIt == VTEs.end())
21136 if (
none_of(
TE->CombinedEntriesWithIndices,
21137 [&](
const auto &
P) { return P.first == VTE->Idx; })) {
21138 Instruction &LastBundleInst = getLastInstructionInBundle(VTE);
21139 if (&LastBundleInst == TEInsertPt ||
21140 !CheckOrdering(&LastBundleInst) ||
21141 CheckNonSchedulableOrdering(VTE, &LastBundleInst))
21145 if (CheckAndUseSameNode(VTE))
21150 if (IsReusedNodeFound)
21152 if (VToTEs.
empty())
21154 if (UsedTEs.
empty()) {
21162 SmallPtrSet<const TreeEntry *, 4> SavedVToTEs(VToTEs);
21164 for (SmallPtrSet<const TreeEntry *, 4> &Set : UsedTEs) {
21168 if (!VToTEs.
empty()) {
21174 VToTEs = SavedVToTEs;
21179 if (Idx == UsedTEs.
size()) {
21183 if (UsedTEs.
size() == 2)
21185 UsedTEs.push_back(SavedVToTEs);
21186 Idx = UsedTEs.
size() - 1;
21192 if (UsedTEs.
empty()) {
21194 return std::nullopt;
21198 if (UsedTEs.
size() == 1) {
21201 UsedTEs.front().
end());
21202 sort(FirstEntries, [](
const TreeEntry *TE1,
const TreeEntry *TE2) {
21203 return TE1->Idx < TE2->Idx;
21206 auto *It =
find_if(FirstEntries, [=](
const TreeEntry *EntryPtr) {
21207 return (EntryPtr->getVectorFactor() ==
TE->Scalars.size() &&
21208 EntryPtr->isSame(
TE->Scalars)) ||
21209 EntryPtr->isSame(VL);
21211 if (It != FirstEntries.end() &&
21212 (IsReusedNodeFound || (*It)->getVectorFactor() == VL.size() ||
21213 ((*It)->getVectorFactor() ==
TE->Scalars.size() &&
21214 TE->ReuseShuffleIndices.size() == VL.size() &&
21215 (*It)->isSame(
TE->Scalars)))) {
21217 if (IsReusedNodeFound || (*It)->getVectorFactor() == VL.size()) {
21218 std::iota(std::next(
Mask.begin(), MaskBase),
21219 std::next(
Mask.begin(), MaskBase + VL.size()), 0);
21221 SmallVector<int> CommonMask =
TE->getCommonMask();
21232 Entries.
push_back(FirstEntries.front());
21234 for (
auto &
P : UsedValuesEntry)
21236 VF = FirstEntries.front()->getVectorFactor();
21239 assert(UsedTEs.
size() == 2 &&
"Expected at max 2 permuted entries.");
21241 DenseMap<int, const TreeEntry *> VFToTE;
21242 for (
const TreeEntry *TE : UsedTEs.front()) {
21243 unsigned VF =
TE->getVectorFactor();
21244 auto It = VFToTE.
find(VF);
21245 if (It != VFToTE.
end()) {
21246 if (It->second->Idx >
TE->Idx)
21247 It->getSecond() =
TE;
21254 UsedTEs.back().
end());
21255 sort(SecondEntries, [](
const TreeEntry *TE1,
const TreeEntry *TE2) {
21256 return TE1->Idx < TE2->Idx;
21258 for (
const TreeEntry *TE : SecondEntries) {
21259 auto It = VFToTE.
find(
TE->getVectorFactor());
21260 if (It != VFToTE.
end()) {
21269 if (Entries.
empty()) {
21271 UsedTEs.front(), [](
const TreeEntry *TE1,
const TreeEntry *TE2) {
21272 return TE1->Idx < TE2->Idx;
21274 Entries.
push_back(SecondEntries.front());
21275 VF = std::max(Entries.
front()->getVectorFactor(),
21276 Entries.
back()->getVectorFactor());
21278 VF = Entries.
front()->getVectorFactor();
21281 for (
const TreeEntry *
E : Entries)
21285 for (
auto &
P : UsedValuesEntry) {
21287 if (ValuesToEntries[Idx].
contains(
P.first)) {
21304 for (
int I = 0,
E =
PHI->getNumIncomingValues();
I <
E; ++
I) {
21306 Value *In1 = PHI1->getIncomingValue(
I);
21324 SmallDenseMap<Value *, bool> MightBeIgnoredCache;
21325 auto MightBeIgnored = [=, &MightBeIgnoredCache](
Value *
V) {
21332 !areAllUsersVectorized(
I, UserIgnoreList) &&
isSimple(
I);
21339 auto NeighborMightBeIgnored = [&](
Value *
V,
int Idx) {
21341 bool UsedInSameVTE =
false;
21342 auto It = UsedValuesEntry.find(
V1);
21343 if (It != UsedValuesEntry.end())
21344 UsedInSameVTE = It->second == UsedValuesEntry.find(V)->second;
21345 return V !=
V1 && MightBeIgnored(
V1) && !UsedInSameVTE &&
21352 SmallBitVector UsedIdxs(Entries.size());
21354 for (
int I = 0,
E = VL.size();
I <
E; ++
I) {
21356 auto It = UsedValuesEntry.find(V);
21357 if (It == UsedValuesEntry.end())
21363 ((
I > 0 && NeighborMightBeIgnored(V,
I - 1)) ||
21364 (
I !=
E - 1 && NeighborMightBeIgnored(V,
I + 1)))))
21366 unsigned Idx = It->second;
21373 for (
unsigned I = 0, Sz = Entries.size();
I < Sz; ++
I) {
21374 if (!UsedIdxs.test(
I))
21380 for (std::pair<unsigned, int> &Pair : EntryLanes)
21381 if (Pair.first ==
I)
21382 Pair.first = TempEntries.
size();
21385 Entries.swap(TempEntries);
21386 if (EntryLanes.size() == Entries.size() &&
21388 .slice(MaskBase,
getNumElems(
TE->Scalars.size(), SliceSize,
21395 return std::nullopt;
21398 bool IsIdentity = Entries.size() == 1;
21401 for (
const std::pair<unsigned, int> &Pair : EntryLanes) {
21402 unsigned Idx = MaskBase + Pair.second;
21405 (ForOrder ? std::distance(
21406 Entries[Pair.first]->Scalars.begin(),
21407 find(Entries[Pair.first]->Scalars, VL[Pair.second]))
21408 : Entries[Pair.first]->findLaneForValue(VL[Pair.second]));
21409 IsIdentity &=
Mask[Idx] == Pair.second;
21411 if (ForOrder || IsIdentity || Entries.empty()) {
21412 switch (Entries.size()) {
21414 if (IsIdentity || EntryLanes.size() > 1 || VL.size() <= 2)
21418 if (EntryLanes.size() > 2 || VL.size() <= 2)
21425 (EntryLanes.size() > Entries.size() || VL.size() <= 2)) {
21427 SmallVector<int> SubMask(std::next(
Mask.begin(), MaskBase),
21428 std::next(
Mask.begin(), MaskBase + VL.size()));
21429 int MinElement = SubMask.
front(), MaxElement = SubMask.
front();
21430 for (
int Idx : SubMask) {
21438 assert(MaxElement >= 0 && MinElement >= 0 &&
21439 MaxElement % VF >= MinElement % VF &&
21440 "Expected at least single element.");
21445 unsigned MinIdx = MinElement % VF;
21448 *TTI, VL.front()->getType(), MinIdx,
SLPReVec);
21449 auto *RegFloorTy =
getWidenedType(VL.front()->getType(), RegFloor);
21450 unsigned RegFloorParts =
21452 if (RegFloorParts > 1)
21456 std::max<unsigned>(VL.size(), (MaxElement % VF) -
Offset + 1);
21458 for (
int &Idx : SubMask) {
21461 Idx = (Idx % VF) -
Offset + (Idx >=
static_cast<int>(VF) ? NewVF : 0);
21471 auto GetShuffleCost = [&,
21472 &TTI = *TTI](ArrayRef<int>
Mask,
21475 if (Entries.size() == 1 && Entries.front()->getInterleaveFactor() > 0 &&
21477 Mask, Entries.front()->getInterleaveFactor()))
21482 VecTy, CostKind, Mask);
21484 InstructionCost ShuffleCost = GetShuffleCost(SubMask, Entries, VecTy);
21486 SmallVector<int> FirstMask(SubMask.begin(), SubMask.end());
21487 if (Entries.size() == 1 || !Entries[0]->isGather()) {
21488 FirstShuffleCost = ShuffleCost;
21492 bool IsIdentity =
true;
21493 for (
auto [
I, Idx] :
enumerate(FirstMask)) {
21494 if (Idx >=
static_cast<int>(NewVF)) {
21499 IsIdentity &=
static_cast<int>(
I) == Idx;
21503 FirstShuffleCost = GetShuffleCost(FirstMask, Entries.front(), VecTy);
21504 FirstShuffleCost +=
21506 MaskVecTy, DemandedElts,
true,
21510 SmallVector<int> SecondMask(SubMask.begin(), SubMask.end());
21511 if (Entries.size() == 1 || !Entries[1]->isGather()) {
21512 SecondShuffleCost = ShuffleCost;
21516 bool IsIdentity =
true;
21517 for (
auto [
I, Idx] :
enumerate(SecondMask)) {
21518 if (Idx <
static_cast<int>(NewVF) && Idx >= 0) {
21524 IsIdentity &=
static_cast<int>(
I) == Idx;
21529 SecondShuffleCost = GetShuffleCost(SecondMask, Entries[1], VecTy);
21530 SecondShuffleCost +=
21532 MaskVecTy, DemandedElts,
true,
21541 MaskVecTy, DemandedElts,
true,
21543 const TreeEntry *BestEntry =
nullptr;
21545 if (FirstShuffleCost < ShuffleCost) {
21546 for (
int &Idx : MaskSlice)
21547 if (Idx >=
static_cast<int>(VF))
21549 BestEntry = Entries.front();
21550 ShuffleCost = FirstShuffleCost;
21552 if (SecondShuffleCost < ShuffleCost) {
21553 for (
int &Idx : MaskSlice) {
21554 if (Idx <
static_cast<int>(VF))
21559 BestEntry = Entries[1];
21560 ShuffleCost = SecondShuffleCost;
21562 if (BuildVectorCost >= ShuffleCost) {
21565 Entries.push_back(BestEntry);
21573 std::fill(std::next(
Mask.begin(), MaskBase),
21575 return std::nullopt;
21579BoUpSLP::isGatherShuffledEntry(
21583 assert(NumParts > 0 && NumParts < VL.
size() &&
21584 "Expected positive number of registers.");
21588 (!GatheredLoadsEntriesFirst.has_value() ||
21590 [](
const std::unique_ptr<TreeEntry> &TE) {
21591 return !
TE->isGather();
21596 "Expected only single user of the gather node.");
21599 if (
TE->UserTreeIndex &&
TE->UserTreeIndex.UserTE->isGather() &&
21600 TE->UserTreeIndex.EdgeIdx == UINT_MAX &&
21602 (
TE->hasState() &&
TE->getOpcode() == Instruction::ExtractElement) ||
21605 getSameValuesTreeEntry(
TE->getMainOp(),
TE->Scalars))))
21610 if (Part * SliceSize >= VL.
size())
21614 SmallVectorImpl<const TreeEntry *> &SubEntries = Entries.emplace_back();
21615 std::optional<TTI::ShuffleKind> SubRes =
21616 isGatherShuffledSingleRegisterEntry(TE, SubVL, Mask, SubEntries, Part,
21617 ForOrder, SliceSize);
21619 SubEntries.
clear();
21622 SubEntries.
front()->getVectorFactor() == VL.
size() &&
21623 (SubEntries.
front()->isSame(
TE->Scalars) ||
21624 SubEntries.
front()->isSame(VL))) {
21626 LocalSubEntries.
swap(SubEntries);
21629 std::iota(
Mask.begin(),
Mask.end(), 0);
21631 for (
int I = 0, Sz = VL.
size();
I < Sz; ++
I)
21634 Entries.emplace_back(1, LocalSubEntries.
front());
21640 [](
const std::optional<TTI::ShuffleKind> &SK) {
return !SK; })) {
21648 Type *ScalarTy)
const {
21649 const unsigned VF = VL.
size();
21656 auto EstimateInsertCost = [&](
unsigned I,
Value *
V) {
21658 if (
V->getType() != ScalarTy)
21659 Cost += TTI->getCastInstrCost(Instruction::Trunc, ScalarTy,
V->getType(),
21663 std::iota(ConstantShuffleMask.begin(), ConstantShuffleMask.end(), 0);
21670 ConstantShuffleMask[
I] =
I + VF;
21673 EstimateInsertCost(
I, V);
21676 bool IsAnyNonUndefConst =
21679 if (!ForPoisonSrc && IsAnyNonUndefConst) {
21686 if (!DemandedElements.
isZero())
21690 false, CostKind, ForPoisonSrc && !IsAnyNonUndefConst, VL);
21694Instruction &BoUpSLP::getLastInstructionInBundle(
const TreeEntry *
E) {
21695 auto It = EntryToLastInstruction.find(
E);
21696 if (It != EntryToLastInstruction.end())
21704 if (
E->hasState()) {
21705 Front =
E->getMainOp();
21706 Opcode =
E->getOpcode();
21713 ((GatheredLoadsEntriesFirst.has_value() && Opcode == Instruction::Load &&
21714 E->isGather() &&
E->Idx < *GatheredLoadsEntriesFirst) ||
21715 E->State == TreeEntry::SplitVectorize ||
E->hasCopyableElements() ||
21717 [=](
Value *V) ->
bool {
21718 if (Opcode == Instruction::GetElementPtr &&
21719 !isa<GetElementPtrInst>(V))
21721 auto *I = dyn_cast<Instruction>(V);
21722 return !I || !E->getMatchingMainOpOrAltOp(I) ||
21723 I->getParent() == BB || isVectorLikeInstWithConstOps(I);
21725 "Expected gathered loads or GEPs or instructions from same basic "
21728 auto FindLastInst = [&]() {
21730 for (
Value *V :
E->Scalars) {
21734 if (
E->isCopyableElement(
I))
21736 if (LastInst->
getParent() ==
I->getParent()) {
21741 assert(((Opcode == Instruction::GetElementPtr &&
21743 E->State == TreeEntry::SplitVectorize ||
21746 (GatheredLoadsEntriesFirst.has_value() &&
21747 Opcode == Instruction::Load &&
E->isGather() &&
21748 E->Idx < *GatheredLoadsEntriesFirst)) &&
21749 "Expected vector-like or non-GEP in GEP node insts only.");
21750 if (!DT->isReachableFromEntry(LastInst->
getParent())) {
21754 if (!DT->isReachableFromEntry(
I->getParent()))
21756 auto *NodeA = DT->getNode(LastInst->
getParent());
21757 auto *NodeB = DT->getNode(
I->getParent());
21758 assert(NodeA &&
"Should only process reachable instructions");
21759 assert(NodeB &&
"Should only process reachable instructions");
21760 assert((NodeA == NodeB) ==
21761 (NodeA->getDFSNumIn() == NodeB->getDFSNumIn()) &&
21762 "Different nodes should have different DFS numbers");
21763 if (NodeA->getDFSNumIn() < NodeB->getDFSNumIn())
21770 auto FindFirstInst = [&]() {
21772 for (
Value *V :
E->Scalars) {
21776 if (
E->isCopyableElement(
I))
21778 if (FirstInst->
getParent() ==
I->getParent()) {
21779 if (
I->comesBefore(FirstInst))
21783 assert(((Opcode == Instruction::GetElementPtr &&
21787 "Expected vector-like or non-GEP in GEP node insts only.");
21788 if (!DT->isReachableFromEntry(FirstInst->
getParent())) {
21792 if (!DT->isReachableFromEntry(
I->getParent()))
21794 auto *NodeA = DT->getNode(FirstInst->
getParent());
21795 auto *NodeB = DT->getNode(
I->getParent());
21796 assert(NodeA &&
"Should only process reachable instructions");
21797 assert(NodeB &&
"Should only process reachable instructions");
21798 assert((NodeA == NodeB) ==
21799 (NodeA->getDFSNumIn() == NodeB->getDFSNumIn()) &&
21800 "Different nodes should have different DFS numbers");
21801 if (NodeA->getDFSNumIn() > NodeB->getDFSNumIn())
21807 if (
E->State == TreeEntry::SplitVectorize) {
21808 Res = FindLastInst();
21810 for (
auto *
E : Entries) {
21813 I = &getLastInstructionInBundle(
E);
21818 EntryToLastInstruction.try_emplace(
E, Res);
21823 if (GatheredLoadsEntriesFirst.has_value() &&
21824 E->Idx >= *GatheredLoadsEntriesFirst && !
E->isGather() &&
21825 Opcode == Instruction::Load) {
21826 Res = FindFirstInst();
21827 EntryToLastInstruction.try_emplace(
E, Res);
21833 auto FindScheduleBundle = [&](
const TreeEntry *
E) ->
const ScheduleBundle * {
21837 const auto *It = BlocksSchedules.find(BB);
21838 if (It == BlocksSchedules.end())
21840 for (
Value *V :
E->Scalars) {
21846 if (Bundles.
empty())
21849 Bundles, [&](ScheduleBundle *
B) {
return B->getTreeEntry() ==
E; });
21850 if (It != Bundles.
end())
21855 const ScheduleBundle *Bundle = FindScheduleBundle(
E);
21856 if (!
E->isGather() && !Bundle) {
21857 if ((Opcode == Instruction::GetElementPtr &&
21860 return !isa<GetElementPtrInst>(V) && isa<Instruction>(V);
21864 return isa<PoisonValue>(V) ||
21866 isa<InsertElementInst, InsertValueInst>(V)) ||
21867 E->isCopyableElement(V) ||
21868 (!isVectorLikeInstWithConstOps(V) &&
21869 isUsedOutsideBlock(V));
21871 (!
E->doesNotNeedToSchedule() ||
21874 if (!isa<Instruction>(V) ||
21875 (E->hasCopyableElements() && E->isCopyableElement(V)))
21877 return !areAllOperandsNonInsts(V);
21880 if (!isa<Instruction>(V) ||
21881 (E->hasCopyableElements() && E->isCopyableElement(V)))
21883 return MustGather.contains(V);
21885 Res = FindLastInst();
21887 Res = FindFirstInst();
21888 EntryToLastInstruction.try_emplace(
E, Res);
21897 assert(!
E->isGather() &&
"Gathered instructions should not be scheduled");
21898 Res = Bundle->getBundle().back()->getInst();
21899 EntryToLastInstruction.try_emplace(
E, Res);
21922 Res = FindLastInst();
21923 assert(Res &&
"Failed to find last instruction in bundle");
21924 EntryToLastInstruction.try_emplace(
E, Res);
21928void BoUpSLP::setInsertPointAfterBundle(
const TreeEntry *
E) {
21929 auto *Front =
E->getMainOp();
21930 Instruction *LastInst = &getLastInstructionInBundle(
E);
21931 assert(LastInst &&
"Failed to find last instruction in bundle");
21936 LastInstIt = LastInst->
getParent()->getFirstNonPHIIt();
21937 if (LastInstIt != LastInst->
getParent()->end() &&
21938 LastInstIt->getParent()->isLandingPad())
21939 LastInstIt = std::next(LastInstIt);
21942 (!
E->isGather() &&
E->State != TreeEntry::SplitVectorize &&
21943 (
E->doesNotNeedToSchedule() ||
21944 (
E->hasCopyableElements() && !
E->isCopyableElement(LastInst) &&
21946 (GatheredLoadsEntriesFirst.has_value() &&
21947 E->Idx >= *GatheredLoadsEntriesFirst && !
E->isGather() &&
21948 E->getOpcode() == Instruction::Load)) {
21949 Builder.SetInsertPoint(LastInst->
getParent(), LastInstIt);
21953 Builder.SetInsertPoint(
21956 if (Instruction *Res = LastInstructionToPos.lookup(LastInst)) {
21959 Res = Builder.CreateAlignedLoad(Builder.getPtrTy(),
21964 if (
E->State != TreeEntry::SplitVectorize)
21965 LastInstructionToPos.try_emplace(LastInst, Res);
21968 Builder.SetCurrentDebugLocation(Front->
getDebugLoc());
21971Value *BoUpSLP::gather(
21973 function_ref<
Value *(
Value *,
Value *, ArrayRef<int>)> CreateShuffle) {
21979 SmallSet<int, 4> PostponedIndices;
21980 Loop *
L = LI->getLoopFor(Builder.GetInsertBlock());
21982 SmallPtrSet<BasicBlock *, 4> Visited;
21983 while (InsertBB && InsertBB != InstBB && Visited.
insert(InsertBB).second)
21984 InsertBB = InsertBB->getSinglePredecessor();
21985 return InsertBB && InsertBB == InstBB;
21987 for (
int I = 0,
E = VL.
size();
I <
E; ++
I) {
21989 if ((CheckPredecessor(Inst->getParent(), Builder.GetInsertBlock()) ||
21991 (L && (!Root ||
L->isLoopInvariant(Root)) &&
L->contains(Inst))) &&
21992 PostponedIndices.
insert(
I).second)
21996 auto &&CreateInsertElement = [
this](
Value *Vec,
Value *
V,
unsigned Pos,
22003 if (
Scalar->getType() != Ty) {
22014 Scalar = Builder.CreateIntCast(
22028 Vec = Builder.CreateInsertElement(Vec, Scalar, Pos);
22033 GatherShuffleExtractSeq.insert(InsElt);
22038 const auto *It =
find_if(Entries, [&](
const TreeEntry *
E) {
22039 return !TransformedToGatherNodes.contains(
E) &&
22040 !DeletedNodes.contains(
E);
22042 if (It != Entries.
end()) {
22044 User *UserOp =
nullptr;
22049 if (
V->getType()->isVectorTy()) {
22051 SV && SV->getOperand(0) != V && SV->getOperand(1) != V) {
22053 auto FindOperand = [](
Value *Vec,
Value *
V) -> Instruction * {
22055 if (SV->getOperand(0) == V)
22057 if (SV->getOperand(1) == V)
22063 if (Instruction *User = FindOperand(SV->getOperand(0), V))
22065 else if (Instruction *User = FindOperand(SV->getOperand(1), V))
22068 "Failed to find shufflevector, caused by resize.");
22075 unsigned FoundLane = (*It)->findLaneForValue(V);
22076 ExternalUses.emplace_back(V,
nullptr, **It, FoundLane);
22077 ExternalUsesWithNonUsers.insert(V);
22083 unsigned FoundLane = (*It)->findLaneForValue(V);
22084 ExternalUses.emplace_back(V, UserOp, **It, FoundLane);
22092 SmallVector<int> NonConsts;
22094 std::iota(
Mask.begin(),
Mask.end(), 0);
22095 Value *OriginalRoot = Root;
22098 SV->getOperand(0)->getType() == VecTy) {
22099 Root = SV->getOperand(0);
22100 Mask.assign(SV->getShuffleMask().begin(), SV->getShuffleMask().end());
22103 for (
int I = 0,
E = VL.
size();
I <
E; ++
I) {
22112 Vec = CreateInsertElement(Vec, VL[
I],
I, ScalarTy);
22117 Vec = OriginalRoot;
22119 Vec = CreateShuffle(Root, Vec, Mask);
22121 OI && OI->use_empty() &&
22122 none_of(VectorizableTree, [&](
const std::unique_ptr<TreeEntry> &TE) {
22123 return TE->VectorizedValue == OI;
22129 for (
int I : NonConsts)
22130 Vec = CreateInsertElement(Vec, VL[
I],
I, ScalarTy);
22133 for (
const std::pair<Value *, unsigned> &Pair : PostponedInsts)
22134 Vec = CreateInsertElement(Vec, Pair.first, Pair.second, ScalarTy);
22172 bool IsFinalized =
false;
22185 class ShuffleIRBuilder {
22198 : Builder(Builder), GatherShuffleExtractSeq(GatherShuffleExtractSeq),
22199 CSEBlocks(CSEBlocks),
DL(DL) {}
22200 ~ShuffleIRBuilder() =
default;
22204 assert(
V1->getType()->isIntOrIntVectorTy() &&
22205 V1->getType()->isIntOrIntVectorTy() &&
22206 "Expected integer vector types only.");
22212 ->getIntegerBitWidth())
22213 V2 = Builder.CreateIntCast(
22216 V1 = Builder.CreateIntCast(
22220 Value *Vec = Builder.CreateShuffleVector(
V1, V2, Mask);
22222 GatherShuffleExtractSeq.insert(
I);
22223 CSEBlocks.insert(
I->getParent());
22232 unsigned VF = Mask.size();
22236 Value *Vec = Builder.CreateShuffleVector(
V1, Mask);
22238 GatherShuffleExtractSeq.insert(
I);
22239 CSEBlocks.insert(
I->getParent());
22243 Value *createIdentity(
Value *V) {
return V; }
22244 Value *createPoison(
Type *Ty,
unsigned VF) {
22254 int VF = std::max(V1VF, V2VF);
22255 int MinVF = std::min(V1VF, V2VF);
22257 std::iota(IdentityMask.
begin(), std::next(IdentityMask.
begin(), MinVF),
22260 Op = Builder.CreateShuffleVector(
Op, IdentityMask);
22262 GatherShuffleExtractSeq.insert(
I);
22263 CSEBlocks.insert(
I->getParent());
22276 assert(
V1 &&
"Expected at least one vector value.");
22277 ShuffleIRBuilder ShuffleBuilder(Builder, R.GatherShuffleExtractSeq,
22278 R.CSEBlocks, *R.DL);
22279 return BaseShuffleAnalysis::createShuffle<Value *>(
22280 V1, V2, Mask, ShuffleBuilder, ScalarTy);
22286 std::optional<bool> IsSigned = std::nullopt) {
22291 return Builder.CreateIntCast(
22292 V,
VectorType::get(ScalarTy->getScalarType(), VecTy->getElementCount()),
22296 Value *getVectorizedValue(
const TreeEntry &E) {
22297 Value *Vec = E.VectorizedValue;
22300 return castToScalarTyElem(Vec,
any_of(E.Scalars, [&](
Value *V) {
22301 return !isa<PoisonValue>(V) &&
22302 !isKnownNonNegative(
22303 V, SimplifyQuery(*R.DL));
22309 : BaseShuffleAnalysis(ScalarTy), Builder(Builder), R(R) {}
22313 ArrayRef<std::optional<TTI::ShuffleKind>> ShuffleKinds,
22314 unsigned NumParts,
bool &UseVecBaseAsInput) {
22315 UseVecBaseAsInput =
false;
22317 Value *VecBase =
nullptr;
22319 if (!E->ReorderIndices.empty()) {
22321 E->ReorderIndices.end());
22324 for (
int I = 0, Sz = Mask.size();
I < Sz; ++
I) {
22329 VecBase = EI->getVectorOperand();
22331 VecBase = TEs.front()->VectorizedValue;
22332 assert(VecBase &&
"Expected vectorized value.");
22333 UniqueBases.
insert(VecBase);
22336 if (!EI->hasOneUse() || R.ExternalUsesAsOriginalScalar.contains(EI) ||
22337 (E->UserTreeIndex && E->UserTreeIndex.EdgeIdx == UINT_MAX &&
22338 !R.isVectorized(EI) &&
22340 count_if(E->UserTreeIndex.UserTE->Scalars,
22341 [&](
Value *V) { return V == EI; })) ||
22342 (NumParts != 1 &&
count(VL, EI) > 1) ||
22344 ArrayRef<TreeEntry *> UTEs = R.getTreeEntries(U);
22345 return UTEs.empty() || UTEs.size() > 1 ||
22347 [&](const TreeEntry *TE) {
22348 return R.DeletedNodes.contains(TE) ||
22349 R.TransformedToGatherNodes.contains(TE);
22355 [&](
const std::unique_ptr<TreeEntry> &TE) {
22356 return TE->UserTreeIndex.UserTE ==
22358 is_contained(VL, EI);
22362 R.eraseInstruction(EI);
22364 if (NumParts == 1 || UniqueBases.
size() == 1) {
22365 assert(VecBase &&
"Expected vectorized value.");
22366 return castToScalarTyElem(VecBase);
22368 UseVecBaseAsInput =
true;
22378 Value *Vec =
nullptr;
22385 constexpr int MaxBases = 2;
22387 auto VLMask =
zip(SubVL, SubMask);
22388 const unsigned VF =
22389 accumulate(VLMask, 0U, [&](
unsigned S,
const auto &
D) {
22396 VecOp = TEs.front()->VectorizedValue;
22397 assert(VecOp &&
"Expected vectorized value.");
22398 const unsigned Size =
22400 return std::max(S,
Size);
22402 for (
const auto [V,
I] : VLMask) {
22407 VecOp = TEs.front()->VectorizedValue;
22408 assert(VecOp &&
"Expected vectorized value.");
22409 VecOp = castToScalarTyElem(VecOp);
22410 Bases[
I / VF] = VecOp;
22412 if (!Bases.front())
22415 if (Bases.back()) {
22416 SubVec = createShuffle(Bases.front(), Bases.back(), SubMask);
22417 TransformToIdentity(SubMask);
22419 SubVec = Bases.front();
22425 ArrayRef<int> SubMask =
22426 Mask.slice(
P * SliceSize,
22429 return all_of(SubMask, [](
int Idx) {
22433 "Expected first part or all previous parts masked.");
22434 copy(SubMask, std::next(VecMask.begin(), Part * SliceSize));
22439 unsigned SubVecVF =
22441 NewVF = std::max(NewVF, SubVecVF);
22444 for (
int &Idx : SubMask)
22447 copy(SubMask, std::next(VecMask.begin(), Part * SliceSize));
22448 Vec = createShuffle(Vec, SubVec, VecMask);
22449 TransformToIdentity(VecMask);
22457 std::optional<Value *>
22463 TEs, [](
const TreeEntry *TE) {
return TE->VectorizedValue; });
22465 return std::nullopt;
22468 auto *ResVecTy =
getWidenedType(ScalarTy, E->getVectorFactor());
22469 return Builder.CreateAlignedLoad(
22476 IsFinalized =
false;
22477 CommonMask.clear();
22483 Value *
V1 = getVectorizedValue(E1);
22484 Value *V2 = getVectorizedValue(E2);
22490 Value *
V1 = getVectorizedValue(E1);
22495 assert(
V1 && V2 && !Mask.empty() &&
"Expected non-empty input vectors.");
22498 "castToScalarTyElem expects V1 and V2 to be FixedVectorType");
22499 V1 = castToScalarTyElem(
V1);
22500 V2 = castToScalarTyElem(V2);
22501 if (InVectors.empty()) {
22502 InVectors.push_back(
V1);
22503 InVectors.push_back(V2);
22504 CommonMask.assign(Mask.begin(), Mask.end());
22507 Value *Vec = InVectors.front();
22508 if (InVectors.size() == 2) {
22509 Vec = createShuffle(Vec, InVectors.back(), CommonMask);
22510 transformMaskAfterShuffle(CommonMask, CommonMask);
22513 Vec = createShuffle(Vec,
nullptr, CommonMask);
22514 transformMaskAfterShuffle(CommonMask, CommonMask);
22516 V1 = createShuffle(
V1, V2, Mask);
22517 unsigned VF = std::max(getVF(
V1), getVF(Vec));
22518 for (
unsigned Idx = 0, Sz = CommonMask.size(); Idx < Sz; ++Idx)
22520 CommonMask[Idx] = Idx + VF;
22521 InVectors.front() = Vec;
22522 if (InVectors.size() == 2)
22523 InVectors.back() =
V1;
22525 InVectors.push_back(
V1);
22530 "castToScalarTyElem expects V1 to be FixedVectorType");
22531 V1 = castToScalarTyElem(
V1);
22532 if (InVectors.empty()) {
22533 InVectors.push_back(
V1);
22534 CommonMask.assign(Mask.begin(), Mask.end());
22537 const auto *It =
find(InVectors,
V1);
22538 if (It == InVectors.end()) {
22539 if (InVectors.size() == 2 ||
22540 InVectors.front()->getType() !=
V1->getType()) {
22541 Value *V = InVectors.front();
22542 if (InVectors.size() == 2) {
22543 V = createShuffle(InVectors.front(), InVectors.back(), CommonMask);
22544 transformMaskAfterShuffle(CommonMask, CommonMask);
22546 CommonMask.size()) {
22547 V = createShuffle(InVectors.front(),
nullptr, CommonMask);
22548 transformMaskAfterShuffle(CommonMask, CommonMask);
22550 unsigned VF = std::max(CommonMask.size(), Mask.size());
22551 for (
unsigned Idx = 0, Sz = CommonMask.size(); Idx < Sz; ++Idx)
22553 CommonMask[Idx] = V->getType() !=
V1->getType()
22555 : Mask[Idx] + getVF(
V1);
22556 if (V->getType() !=
V1->getType())
22557 V1 = createShuffle(
V1,
nullptr, Mask);
22558 InVectors.front() = V;
22559 if (InVectors.size() == 2)
22560 InVectors.back() =
V1;
22562 InVectors.push_back(
V1);
22567 for (
unsigned Idx = 0, Sz = CommonMask.size(); Idx < Sz; ++Idx)
22569 InVectors.push_back(
V1);
22574 for (
Value *V : InVectors)
22575 VF = std::max(VF, getVF(V));
22576 for (
unsigned Idx = 0, Sz = CommonMask.size(); Idx < Sz; ++Idx)
22578 CommonMask[Idx] = Mask[Idx] + (It == InVectors.begin() ? 0 : VF);
22587 Value *Root =
nullptr) {
22588 return R.gather(VL, Root, ScalarTy,
22590 return createShuffle(
V1, V2, Mask);
22599 ArrayRef<std::pair<const TreeEntry *, unsigned>> SubVectors,
22604 IsFinalized =
true;
22607 if (InVectors.
size() == 2) {
22608 Vec = createShuffle(Vec, InVectors.
back(), CommonMask);
22611 Vec = createShuffle(Vec,
nullptr, CommonMask);
22613 transformMaskAfterShuffle(CommonMask, CommonMask);
22615 "Expected vector length for the final value before action.");
22619 std::iota(ResizeMask.begin(), std::next(ResizeMask.begin(), VecVF), 0);
22620 Vec = createShuffle(Vec,
nullptr, ResizeMask);
22622 Action(Vec, CommonMask, [
this](
Value *
V1,
Value *V2, ArrayRef<int> Mask) {
22623 return createShuffle(
V1, V2, Mask);
22625 InVectors.
front() = Vec;
22627 if (!SubVectors.empty()) {
22629 if (InVectors.
size() == 2) {
22630 Vec = createShuffle(Vec, InVectors.
back(), CommonMask);
22633 Vec = createShuffle(Vec,
nullptr, CommonMask);
22635 transformMaskAfterShuffle(CommonMask, CommonMask);
22636 auto CreateSubVectors = [&](
Value *Vec,
22637 SmallVectorImpl<int> &CommonMask) {
22638 for (
auto [
E, Idx] : SubVectors) {
22639 Value *
V = getVectorizedValue(*
E);
22646 Type *OrigScalarTy = ScalarTy;
22649 Builder, Vec, V, InsertionIndex,
22650 std::bind(&ShuffleInstructionBuilder::createShuffle,
this, _1, _2,
22652 ScalarTy = OrigScalarTy;
22653 if (!CommonMask.
empty()) {
22654 std::iota(std::next(CommonMask.
begin(), Idx),
22655 std::next(CommonMask.
begin(), Idx +
E->getVectorFactor()),
22661 if (SubVectorsMask.
empty()) {
22662 Vec = CreateSubVectors(Vec, CommonMask);
22665 copy(SubVectorsMask, SVMask.begin());
22666 for (
auto [I1, I2] :
zip(SVMask, CommonMask)) {
22669 I1 = I2 + CommonMask.
size();
22674 Vec = createShuffle(InsertVec, Vec, SVMask);
22675 transformMaskAfterShuffle(CommonMask, SVMask);
22677 InVectors.
front() = Vec;
22680 if (!ExtMask.
empty()) {
22681 if (CommonMask.
empty()) {
22685 for (
int I = 0, Sz = ExtMask.
size();
I < Sz; ++
I) {
22688 NewMask[
I] = CommonMask[ExtMask[
I]];
22690 CommonMask.
swap(NewMask);
22693 if (CommonMask.
empty()) {
22694 assert(InVectors.
size() == 1 &&
"Expected only one vector with no mask");
22695 return InVectors.
front();
22697 if (InVectors.
size() == 2)
22698 return createShuffle(InVectors.
front(), InVectors.
back(), CommonMask);
22699 return createShuffle(InVectors.
front(),
nullptr, CommonMask);
22703 assert((IsFinalized || CommonMask.empty()) &&
22704 "Shuffle construction must be finalized.");
22708Value *BoUpSLP::vectorizeOperand(TreeEntry *E,
unsigned NodeIdx) {
22712template <
typename BVTy,
typename ResTy,
typename... Args>
22713ResTy BoUpSLP::processBuildVector(
const TreeEntry *E,
Type *ScalarTy,
22715 assert((E->isGather() || TransformedToGatherNodes.contains(E)) &&
22716 "Expected gather node.");
22717 unsigned VF = E->getVectorFactor();
22719 bool NeedFreeze =
false;
22723 E->CombinedEntriesWithIndices.size());
22724 if (E->State == TreeEntry::SplitVectorize &&
22725 TransformedToGatherNodes.contains(E)) {
22726 SubVectors.
clear();
22729 for (
auto [EIdx, Idx] : E->CombinedEntriesWithIndices)
22731 .slice(Idx, VectorizableTree[EIdx]->getVectorFactor()),
22734 E->CombinedEntriesWithIndices, SubVectors.
begin(), [&](
const auto &
P) {
22735 return std::make_pair(VectorizableTree[P.first].get(), P.second);
22741 E->ReorderIndices.end());
22742 if (!ReorderMask.
empty())
22748 if (!SubVectors.
empty() && !SubVectorsMask.
empty()) {
22750 if (E->Scalars[
I] == GatheredScalars[ReorderMask[
I]])
22753 SubVectorsMask.
clear();
22757 unsigned I,
unsigned SliceSize,
22758 bool IsNotPoisonous) {
22760 return isa<UndefValue>(V) && !isa<PoisonValue>(V);
22763 TreeEntry *UserTE = E->UserTreeIndex.UserTE;
22764 unsigned EdgeIdx = E->UserTreeIndex.EdgeIdx;
22765 if (UserTE->getNumOperands() != 2)
22767 if (!IsNotPoisonous) {
22768 auto *It =
find_if(
ArrayRef(VectorizableTree).drop_front(UserTE->Idx + 1),
22769 [=](
const std::unique_ptr<TreeEntry> &TE) {
22770 return TE->UserTreeIndex.UserTE == UserTE &&
22771 TE->UserTreeIndex.EdgeIdx != EdgeIdx;
22773 if (It == VectorizableTree.end())
22776 if (!(*It)->ReorderIndices.empty()) {
22780 if (!
all_of(
zip(GatheredScalars, GS), [&](
const auto &
P) {
22781 Value *V0 = std::get<0>(
P);
22790 if ((Mask.size() < InputVF &&
22793 (Mask.size() == InputVF &&
22796 std::next(Mask.begin(),
I * SliceSize),
22797 std::next(Mask.begin(),
22804 std::next(Mask.begin(),
I * SliceSize),
22805 std::next(Mask.begin(),
22811 BVTy ShuffleBuilder(ScalarTy, Params...);
22812 ResTy Res = ResTy();
22816 Value *ExtractVecBase =
nullptr;
22817 bool UseVecBaseAsInput =
false;
22820 Type *OrigScalarTy = GatheredScalars.
front()->getType();
22825 bool Resized =
false;
22827 tryToGatherExtractElements(GatheredScalars, ExtractMask, NumParts);
22828 if (!ExtractShuffles.
empty()) {
22830 for (
auto [Idx,
I] :
enumerate(ExtractMask)) {
22836 ExtractEntries.
append(TEs.begin(), TEs.end());
22838 if (std::optional<ResTy> Delayed =
22839 ShuffleBuilder.needToDelay(E, ExtractEntries)) {
22841 PostponedGathers.insert(E);
22846 if (
Value *VecBase = ShuffleBuilder.adjustExtracts(
22847 E, ExtractMask, ExtractShuffles, NumParts, UseVecBaseAsInput)) {
22848 ExtractVecBase = VecBase;
22850 if (VF == VecBaseTy->getNumElements() &&
22851 GatheredScalars.
size() != VF) {
22853 GatheredScalars.
append(VF - GatheredScalars.
size(),
22861 if (!ExtractShuffles.
empty() || !E->hasState() ||
22862 E->getOpcode() != Instruction::Load ||
22863 (((E->hasState() && E->getOpcode() == Instruction::Load) ||
22867 return isa<LoadInst>(V) && isVectorized(V);
22869 (E->hasState() && E->isAltShuffle()) ||
22870 all_of(E->Scalars, [
this](
Value *V) { return isVectorized(V); }) ||
22872 (E->Scalars != GatheredScalars && GatheredScalars.
size() <= 2)) {
22874 isGatherShuffledEntry(E, GatheredScalars, Mask, Entries, NumParts);
22876 if (!GatherShuffles.
empty()) {
22877 if (std::optional<ResTy> Delayed =
22878 ShuffleBuilder.needToDelay(E, Entries)) {
22880 PostponedGathers.insert(E);
22887 auto IsFullVectorMatch = [&](
const TreeEntry *FrontTE) {
22891 Expanded[
I] = CommonMask.
empty() ? E->Scalars[
I]
22894 : E->Scalars[CommonMask[
I]];
22895 return FrontTE->isSame(Expanded);
22897 if (GatherShuffles.
size() == 1 &&
22899 (Entries.
front().front()->isSame(E->Scalars) ||
22900 IsFullVectorMatch(Entries.
front().front()))) {
22903 LLVM_DEBUG(
dbgs() <<
"SLP: perfect diamond match for gather bundle "
22906 Mask.resize(E->Scalars.size());
22907 const TreeEntry *FrontTE = Entries.
front().front();
22908 if (FrontTE->ReorderIndices.empty() && E->ReorderIndices.empty() &&
22909 ((FrontTE->ReuseShuffleIndices.empty() &&
22910 E->Scalars.size() == FrontTE->Scalars.size()) ||
22911 (E->Scalars.size() == FrontTE->ReuseShuffleIndices.size()))) {
22912 std::iota(Mask.begin(), Mask.end(), 0);
22919 Mask[
I] = FrontTE->findLaneForValue(V);
22924 ShuffleBuilder.resetForSameNode();
22926 if ((IsFullVectorMatch(FrontTE) &&
22927 FrontTE->ReuseShuffleIndices.empty() &&
22928 FrontTE->ReorderIndices.empty() &&
22929 E->getVectorFactor() == FrontTE->getVectorFactor()) ||
22930 (
equal(E->Scalars, FrontTE->Scalars) &&
22931 equal(E->ReorderIndices, FrontTE->ReorderIndices) &&
22932 equal(E->ReuseShuffleIndices, FrontTE->ReuseShuffleIndices))) {
22933 Mask.resize(FrontTE->getVectorFactor());
22934 std::iota(Mask.begin(), Mask.end(), 0);
22935 ShuffleBuilder.add(*FrontTE, Mask);
22936 Res = ShuffleBuilder.finalize({}, {}, {});
22938 ShuffleBuilder.add(*FrontTE, Mask);
22939 Res = ShuffleBuilder.finalize(E->getCommonMask(), {}, {});
22944 if (GatheredScalars.
size() != VF &&
22946 return any_of(TEs, [&](
const TreeEntry *TE) {
22947 return TE->getVectorFactor() == VF;
22950 GatheredScalars.
append(VF - GatheredScalars.
size(),
22954 for (
int I = 0, Sz = Mask.size();
I < Sz; ++
I) {
22962 bool IsRootPoison) {
22965 bool IsSplat = IsRootPoison &&
isSplat(Scalars) &&
22972 int NumNonConsts = 0;
22991 Scalars.
front() = OrigV;
22994 const auto Res = UniquePositions.
try_emplace(OrigV,
I);
22995 Scalars[Res.first->second] = OrigV;
22996 ReuseMask[
I] = Res.first->second;
22999 if (NumNonConsts == 1) {
23004 if (!UndefPos.
empty() && UndefPos.
front() == 0)
23007 ReuseMask[SinglePos] = SinglePos;
23008 }
else if (!UndefPos.
empty() && IsSplat) {
23015 (E->UserTreeIndex &&
any_of(V->uses(), [E](
const Use &U) {
23018 return E->UserTreeIndex.EdgeIdx != U.getOperandNo() &&
23019 is_contained(E->UserTreeIndex.UserTE->Scalars,
23023 if (It != Scalars.
end()) {
23025 int Pos = std::distance(Scalars.
begin(), It);
23026 for (
int I : UndefPos) {
23028 ReuseMask[
I] = Pos;
23037 for (
int I : UndefPos) {
23046 if (!ExtractShuffles.
empty() || !GatherShuffles.
empty()) {
23047 bool IsNonPoisoned =
true;
23048 bool IsUsedInExpr =
true;
23049 Value *Vec1 =
nullptr;
23050 if (!ExtractShuffles.
empty()) {
23054 Value *Vec2 =
nullptr;
23055 for (
unsigned I = 0, Sz = ExtractMask.
size();
I < Sz; ++
I) {
23059 if (UseVecBaseAsInput) {
23060 Vec1 = ExtractVecBase;
23062 for (
unsigned I = 0, Sz = ExtractMask.
size();
I < Sz; ++
I) {
23068 Value *VecOp = EI->getVectorOperand();
23070 !TEs.
empty() && TEs.front()->VectorizedValue)
23071 VecOp = TEs.front()->VectorizedValue;
23074 }
else if (Vec1 != VecOp) {
23075 assert((!Vec2 || Vec2 == VecOp) &&
23076 "Expected only 1 or 2 vectors shuffle.");
23082 IsUsedInExpr =
false;
23085 ShuffleBuilder.add(Vec1, Vec2, ExtractMask);
23088 IsUsedInExpr &= FindReusedSplat(
23091 ExtractMask.
size(), IsNotPoisonedVec);
23092 ShuffleBuilder.add(Vec1, ExtractMask,
true);
23093 IsNonPoisoned &= IsNotPoisonedVec;
23095 IsUsedInExpr =
false;
23100 if (!GatherShuffles.
empty()) {
23102 if (Mask.size() == E->Scalars.size())
23107 for (
const auto [
I, TEs] :
enumerate(Entries)) {
23110 "No shuffles with empty entries list expected.");
23113 assert((TEs.size() == 1 || TEs.size() == 2) &&
23114 "Expected shuffle of 1 or 2 entries.");
23115 unsigned Limit =
getNumElems(Mask.size(), SliceSize,
I);
23118 copy(SubMask, std::next(VecMask.
begin(),
I * SliceSize));
23119 if (TEs.size() == 1) {
23120 bool IsNotPoisonedVec =
23121 TEs.front()->VectorizedValue
23125 FindReusedSplat(VecMask, TEs.
front()->getVectorFactor(),
I,
23126 SliceSize, IsNotPoisonedVec);
23127 ShuffleBuilder.add(*TEs.front(), VecMask);
23128 IsNonPoisoned &= IsNotPoisonedVec;
23130 IsUsedInExpr =
false;
23131 ShuffleBuilder.add(*TEs.front(), *TEs.back(), VecMask);
23132 if (TEs.front()->VectorizedValue && TEs.back()->VectorizedValue)
23143 int EMSz = ExtractMask.
size();
23144 int MSz = Mask.size();
23147 bool IsSingleShuffle = ExtractShuffles.
empty() || GatherShuffles.
empty();
23148 bool IsIdentityShuffle =
23149 ((UseVecBaseAsInput ||
23151 [](
const std::optional<TTI::ShuffleKind> &SK) {
23155 none_of(ExtractMask, [&](
int I) {
return I >= EMSz; }) &&
23157 (!GatherShuffles.
empty() &&
23159 [](
const std::optional<TTI::ShuffleKind> &SK) {
23163 none_of(Mask, [&](
int I) {
return I >= MSz; }) &&
23165 bool EnoughConstsForShuffle =
23175 (!IsIdentityShuffle ||
23176 (GatheredScalars.
size() == 2 &&
23184 for (
int I = 0, Sz = GatheredScalars.
size();
I < Sz; ++
I) {
23185 if (EnoughConstsForShuffle &&
isa<Constant>(GatheredScalars[
I]))
23193 TryPackScalars(GatheredScalars, BVMask,
true);
23194 Value *BV = ShuffleBuilder.gather(GatheredScalars, BVMask.
size());
23195 ShuffleBuilder.add(BV, BVMask);
23199 (IsSingleShuffle && ((IsIdentityShuffle &&
23202 Res = ShuffleBuilder.finalize(E->ReuseShuffleIndices, SubVectors,
23205 Res = ShuffleBuilder.finalize(
23206 E->ReuseShuffleIndices, SubVectors, SubVectorsMask, E->Scalars.
size(),
23208 bool IsSplat = isSplat(NonConstants);
23209 SmallVector<int> BVMask(Mask.size(), PoisonMaskElem);
23210 TryPackScalars(NonConstants, BVMask, false);
23211 auto CheckIfSplatIsProfitable = [&]() {
23214 Value *V = *find_if_not(NonConstants, IsaPred<UndefValue>);
23215 if (isa<ExtractElementInst>(V) || isVectorized(V))
23217 InstructionCost SplatCost = TTI->getVectorInstrCost(
23218 Instruction::InsertElement, VecTy, CostKind, 0,
23219 PoisonValue::get(VecTy), V);
23220 SmallVector<int> NewMask(Mask.begin(), Mask.end());
23221 for (auto [Idx, I] : enumerate(BVMask))
23222 if (I != PoisonMaskElem)
23223 NewMask[Idx] = Mask.size();
23225 getShuffleCost(*TTI, TTI::SK_PermuteTwoSrc,
23226 cast<VectorType>(VecTy), CostKind, NewMask);
23227 InstructionCost BVCost = TTI->getVectorInstrCost(
23228 Instruction::InsertElement, VecTy, CostKind,
23229 *find_if(Mask, not_equal_to(PoisonMaskElem)), Vec, V);
23231 if (count(BVMask, PoisonMaskElem) <
23232 static_cast<int>(BVMask.size() - 1)) {
23233 SmallVector<int> NewMask(Mask.begin(), Mask.end());
23234 for (auto [Idx, I] : enumerate(BVMask))
23235 if (I != PoisonMaskElem)
23238 getShuffleCost(*TTI, TTI::SK_PermuteSingleSrc,
23239 cast<VectorType>(VecTy), CostKind, NewMask);
23241 return SplatCost <= BVCost;
23243 if (!IsSplat || Mask.size() <= 2 || !CheckIfSplatIsProfitable()) {
23247 Vec = ShuffleBuilder.gather(NonConstants, Mask.size(), Vec);
23253 Value *BV = ShuffleBuilder.gather(
Values, BVMask.size());
23256 return I == PoisonMaskElem ? PoisonMaskElem : 0;
23259 BV = CreateShuffle(BV,
nullptr, SplatMask);
23262 Mask[Idx] = BVMask.size() + Idx;
23263 Vec = CreateShuffle(Vec, BV, Mask);
23272 TryPackScalars(GatheredScalars, ReuseMask,
true);
23273 Value *BV = ShuffleBuilder.gather(GatheredScalars, ReuseMask.size());
23274 ShuffleBuilder.add(BV, ReuseMask);
23275 Res = ShuffleBuilder.finalize(E->ReuseShuffleIndices, SubVectors,
23280 for (
auto [
I, V] :
enumerate(GatheredScalars)) {
23284 Value *BV = ShuffleBuilder.gather(GatheredScalars);
23285 ShuffleBuilder.add(BV, Mask);
23286 Res = ShuffleBuilder.finalize(
E->ReuseShuffleIndices, SubVectors,
23291 Res = ShuffleBuilder.createFreeze(Res);
23295Value *BoUpSLP::createBuildVector(
const TreeEntry *
E,
Type *ScalarTy) {
23297 if (
E->State != TreeEntry::SplitVectorize ||
23298 !TransformedToGatherNodes.contains(
E)) {
23299 for (
auto [EIdx,
_] :
E->CombinedEntriesWithIndices)
23302 return processBuildVector<ShuffleInstructionBuilder, Value *>(
E, ScalarTy,
23310 for (
Value *V : VL)
23323 IRBuilderBase::InsertPointGuard Guard(Builder);
23325 Value *
V =
E->Scalars.front();
23327 auto It = MinBWs.find(
E);
23328 if (It != MinBWs.end()) {
23334 if (
E->VectorizedValue)
23335 return E->VectorizedValue;
23337 if (
E->isGather() || TransformedToGatherNodes.contains(
E)) {
23339 if (
E->hasState() &&
E->Idx == 0 && !UserIgnoreList)
23340 setInsertPointAfterBundle(
E);
23341 Value *Vec = createBuildVector(
E, ScalarTy);
23342 E->VectorizedValue = Vec;
23345 if (
E->State == TreeEntry::SplitVectorize) {
23346 assert(
E->CombinedEntriesWithIndices.size() == 2 &&
23347 "Expected exactly 2 combined entries.");
23348 setInsertPointAfterBundle(
E);
23350 *VectorizableTree[
E->CombinedEntriesWithIndices.front().first];
23352 ArrayRef(
E->Scalars).take_front(OpTE1.getVectorFactor())) &&
23353 "Expected same first part of scalars.");
23356 *VectorizableTree[
E->CombinedEntriesWithIndices.back().first];
23358 OpTE2.isSame(
ArrayRef(
E->Scalars).take_back(OpTE2.getVectorFactor())) &&
23359 "Expected same second part of scalars.");
23361 auto GetOperandSignedness = [&](
const TreeEntry *OpE) {
23362 bool IsSigned =
false;
23363 auto It = MinBWs.find(OpE);
23364 if (It != MinBWs.end())
23365 IsSigned = It->second.second;
23368 if (isa<PoisonValue>(V))
23370 return !isKnownNonNegative(R, SimplifyQuery(*DL));
23377 Op1 = Builder.CreateIntCast(
23382 GetOperandSignedness(&OpTE1));
23387 Op2 = Builder.CreateIntCast(
23392 GetOperandSignedness(&OpTE2));
23394 if (
E->ReorderIndices.empty()) {
23398 std::next(
Mask.begin(),
E->CombinedEntriesWithIndices.back().second),
23401 if (ScalarTyNumElements != 1) {
23405 Value *Vec = Builder.CreateShuffleVector(Op1, Mask);
23407 E->CombinedEntriesWithIndices.back().second *
23408 ScalarTyNumElements);
23409 E->VectorizedValue = Vec;
23412 unsigned CommonVF =
23413 std::max(OpTE1.getVectorFactor(), OpTE2.getVectorFactor());
23420 Op1 = Builder.CreateShuffleVector(Op1, Mask);
23426 Op2 = Builder.CreateShuffleVector(Op2, Mask);
23428 Value *Vec = Builder.CreateShuffleVector(Op1, Op2,
E->getSplitMask());
23429 E->VectorizedValue = Vec;
23433 bool IsReverseOrder =
23435 auto FinalShuffle = [&](
Value *
V,
const TreeEntry *
E) {
23438 assert(
E->ReorderIndices.empty() &&
23439 "Expected no reordering for struct types.");
23440 assert(
E->ReuseShuffleIndices.empty() &&
23441 "Expected no reuse shuffle indices for struct types.");
23445 if ((
E->State == TreeEntry::StridedVectorize && IsReverseOrder) ||
23446 E->State == TreeEntry::CompressVectorize) {
23447 ShuffleBuilder.addOrdered(V, {});
23448 }
else if (
E->getOpcode() == Instruction::Store &&
23449 (
E->State == TreeEntry::Vectorize ||
23450 E->State == TreeEntry::StridedVectorize ||
23451 E->State == TreeEntry::ExpandVectorize)) {
23452 ArrayRef<int>
Mask =
23453 ArrayRef(
reinterpret_cast<const int *
>(
E->ReorderIndices.begin()),
23454 E->ReorderIndices.size());
23455 ShuffleBuilder.add(V, Mask);
23457 ShuffleBuilder.addOrdered(V,
E->ReorderIndices);
23460 E->CombinedEntriesWithIndices.size());
23462 E->CombinedEntriesWithIndices, SubVectors.begin(), [&](
const auto &
P) {
23463 return std::make_pair(VectorizableTree[P.first].get(), P.second);
23466 (
E->CombinedEntriesWithIndices.empty() ||
E->ReorderIndices.empty()) &&
23467 "Expected either combined subnodes or reordering");
23468 return ShuffleBuilder.finalize(
E->ReuseShuffleIndices, SubVectors, {});
23471 assert(!
E->isGather() &&
"Unhandled state");
23472 unsigned ShuffleOrOp =
23473 E->isAltShuffle() ? (unsigned)Instruction::ShuffleVector :
E->
getOpcode();
23474 if (!
E->isAltShuffle()) {
23475 switch (E->CombinedOp) {
23476 case TreeEntry::ReducedBitcast:
23477 case TreeEntry::ReducedBitcastBSwap:
23478 case TreeEntry::ReducedBitcastLoads:
23479 case TreeEntry::ReducedBitcastBSwapLoads:
23480 case TreeEntry::ReducedCmpBitcast:
23481 ShuffleOrOp = E->CombinedOp;
23488 auto GetOperandSignedness = [&](
unsigned Idx) {
23489 const TreeEntry *OpE = getOperandEntry(
E, Idx);
23490 bool IsSigned =
false;
23491 auto It = MinBWs.find(OpE);
23492 if (It != MinBWs.end())
23493 IsSigned = It->second.second;
23496 if (isa<PoisonValue>(V))
23498 return !isKnownNonNegative(R, SimplifyQuery(*DL));
23502 auto PropagateIRFlags = [&](
Value *
V,
unsigned Opcode = 0,
23505 SmallSetVector<Value *, 4> UniqueInsts;
23506 for (
Value *Scalar : Scalars) {
23510 if (
E->hasCopyableElements() &&
E->isCopyableElement(
I))
23515 Opcode =
E->getOpcode();
23528 bool AllNoNaNs =
true;
23529 bool AllNoInfs =
true;
23530 for (
Value *Scalar : Scalars) {
23531 if (!
E->isCopyableElement(Scalar))
23534 AllNoNaNs &= FPMO->hasNoNaNs();
23535 AllNoInfs &= FPMO->hasNoInfs();
23539 AllNoNaNs &= !CFP->isNaN();
23540 AllNoInfs &= !CFP->isInfinity();
23548 I->setHasNoNaNs(
false);
23550 I->setHasNoInfs(
false);
23553 if (!MinBWs.contains(
E) && Opcode == Instruction::Sub &&
23554 (
E->hasCopyableElements() ||
any_of(Scalars, [](
Value *Scalar) {
23558 I->setHasNoUnsignedWrap(
false);
23561 if (!MinBWs.contains(
E) && Opcode == Instruction::Sub &&
23564 if (!SI ||
SI->getOpcode() != Instruction::Sub || !
isCommutative(SI))
23566 return any_of(
SI->uses(), [](
const Use &U) {
23568 return match(U.getUser(),
23569 m_ICmp(Pred, m_Specific(U.get()), m_Zero())) &&
23570 ICmpInst::isEquality(Pred);
23573 I->setHasNoSignedWrap(
false);
23578 if (!MinBWs.contains(
E) &&
23579 (Opcode == Instruction::Add || Opcode == Instruction::Sub)) {
23580 for (
Value *V : UniqueInsts) {
23582 if (
SI->getOpcode() == Opcode ||
23588 if (!CI || CI->isZero())
23590 I->setHasNoUnsignedWrap(
false);
23591 if (CI->getValue().isMinSignedValue())
23592 I->setHasNoSignedWrap(
false);
23599 if (!MinBWs.contains(
E) && Opcode == Instruction::Shl &&
23602 if (
SI->getOpcode() != Instruction::Mul)
23605 const auto *CI = dyn_cast<ConstantInt>(Op);
23606 return CI && CI->getValue().isMinSignedValue();
23609 I->setHasNoSignedWrap(
false);
23613 if (!MinBWs.contains(
E) && Opcode == Instruction::Mul &&
23616 if (
SI->getOpcode() != Instruction::Shl)
23619 return CI && CI->getValue() == CI->getBitWidth() - 1;
23621 I->setHasNoSignedWrap(
false);
23628 ICmp->getOperand(0)->getType()->getScalarType() !=
23630 ((!GetOperandSignedness(0) &&
23632 (!GetOperandSignedness(1) &&
23635 bool SignFlip = !SignChange &&
any_of(
E->Scalars, [&](
Value *Scalar) {
23636 auto *LaneCI = dyn_cast<ICmpInst>(Scalar);
23639 auto *OrigC = dyn_cast<ConstantInt>(LaneCI->getOperand(1));
23642 ConstantInt *AdjC =
23643 CmpSamePredicateHelper::getAdjustedConstant(LaneCI, P0);
23644 return AdjC && AdjC->isNegative() != OrigC->isNegative();
23646 if (SignChange || SignFlip)
23647 ICmp->setSameSign(
false);
23651 switch (ShuffleOrOp) {
23652 case Instruction::PHI: {
23653 assert((
E->ReorderIndices.empty() || !
E->ReuseShuffleIndices.empty() ||
23655 "PHI reordering is free.");
23657 Builder.SetInsertPoint(PH->getParent(),
23658 PH->getParent()->getFirstNonPHIIt());
23660 PHINode *NewPhi = Builder.CreatePHI(VecTy, PH->getNumIncomingValues());
23664 Builder.SetInsertPoint(PH->getParent(),
23665 PH->getParent()->getFirstInsertionPt());
23668 V = FinalShuffle(V,
E);
23670 E->VectorizedValue =
V;
23677 SmallDenseMap<BasicBlock *, unsigned, 4> VisitedBBs;
23683 LLVM_DEBUG(
dbgs() <<
"SLP: Diamond merged for " << *VL0 <<
".\n");
23689 TreeEntry *OpTE = getOperandEntry(
E,
I);
23690 if (OpTE->isGather() || DeletedNodes.contains(OpTE) ||
23691 TransformedToGatherNodes.contains(OpTE)) {
23694 assert(!OpTE->VectorizedValue &&
"Expected no vectorized value.");
23695 OpTE->VectorizedValue = VecOp;
23702 Value *Vec = vectorizeOperand(
E,
I);
23703 if (VecTy != Vec->
getType()) {
23705 MinBWs.contains(getOperandEntry(
E,
I))) &&
23706 "Expected item in MinBWs.");
23707 Vec = Builder.CreateIntCast(Vec, VecTy, GetOperandSignedness(
I));
23713 "Invalid number of incoming values");
23714 assert(
E->VectorizedValue &&
"Expected vectorized value.");
23715 return E->VectorizedValue;
23718 case Instruction::ExtractElement: {
23719 Value *
V =
E->getSingleOperand(0);
23720 setInsertPointAfterBundle(
E);
23721 V = FinalShuffle(V,
E);
23726 if (
E->hasCopyableElements()) {
23727 assert(
E->ReorderIndices.empty() &&
E->ReuseShuffleIndices.empty() &&
23728 "Copyable extract lanes require identity order and no reuse.");
23729 for (
auto [Idx, Scalar] :
enumerate(
E->Scalars))
23730 if (
E->isCopyableElement(Scalar))
23731 V = Builder.CreateInsertElement(V, Scalar, Builder.getInt32(Idx));
23733 E->VectorizedValue =
V;
23736 case Instruction::ExtractValue: {
23737 if (!
E->StructEVIndices.empty()) {
23738 setInsertPointAfterBundle(
E);
23739 Value *
V = vectorizeOperand(
E, 0);
23740 V = Builder.CreateExtractValue(V,
E->StructEVIndices);
23743 V = FinalShuffle(V,
E);
23744 E->VectorizedValue =
V;
23748 Builder.SetInsertPoint(LI);
23749 Value *Ptr = LI->getPointerOperand();
23750 LoadInst *
V = Builder.CreateAlignedLoad(VecTy, Ptr, LI->getAlign());
23751 Value *NewV = PropagateIRFlags(V);
23752 NewV = FinalShuffle(NewV,
E);
23753 E->VectorizedValue = NewV;
23756 case Instruction::InsertValue:
23757 case Instruction::InsertElement: {
23758 assert(
E->ReuseShuffleIndices.empty() &&
"All inserts should be unique");
23759 if (
const TreeEntry *OpE = getOperandEntry(
E, 1);
23760 OpE && !OpE->isGather() && OpE->hasState() &&
23761 !OpE->hasCopyableElements())
23764 setInsertPointAfterBundle(
E);
23765 Value *
V = vectorizeOperand(
E, 1);
23767 Type *ScalarTy =
Op.front()->getType();
23770 std::pair<unsigned, bool> Res = MinBWs.lookup(getOperandEntry(
E, 1));
23771 assert(Res.first > 0 &&
"Expected item in MinBWs.");
23772 V = Builder.CreateIntCast(
23782 return !is_contained(E->Scalars, cast<Instruction>(V)->getOperand(0));
23784 const unsigned NumScalars =
E->Scalars.size();
23789 assert(
Offset < NumElts &&
"Failed to find vector index offset");
23792 SmallVector<int>
Mask;
23793 if (!
E->ReorderIndices.empty()) {
23798 std::iota(
Mask.begin(), std::next(
Mask.begin(), NumScalars), 0);
23801 bool IsIdentity =
true;
23803 Mask.swap(PrevMask);
23804 for (
unsigned I = 0;
I < NumScalars; ++
I) {
23807 IsIdentity &= InsertIdx -
Offset ==
I;
23810 if (!IsIdentity || NumElts != NumScalars) {
23811 Value *V2 =
nullptr;
23812 bool IsVNonPoisonous =
23814 SmallVector<int> InsertMask(Mask);
23815 if (NumElts != NumScalars &&
Offset == 0) {
23825 InsertMask[*InsertIdx] = *InsertIdx;
23833 buildUseMask(NumElts, InsertMask, UseMask::UndefsAsMask);
23834 SmallBitVector IsFirstPoison =
23836 SmallBitVector IsFirstUndef =
23838 if (!IsFirstPoison.
all()) {
23840 for (
unsigned I = 0;
I < NumElts;
I++) {
23842 IsFirstUndef.
test(
I)) {
23843 if (IsVNonPoisonous) {
23844 InsertMask[
I] =
I < NumScalars ?
I : 0;
23849 if (Idx >= NumScalars)
23850 Idx = NumScalars - 1;
23851 InsertMask[
I] = NumScalars + Idx;
23864 V = Builder.CreateShuffleVector(V, V2, InsertMask);
23866 GatherShuffleExtractSeq.insert(
I);
23867 CSEBlocks.insert(
I->getParent());
23872 for (
unsigned I = 0;
I < NumElts;
I++) {
23877 buildUseMask(NumElts, InsertMask, UseMask::UndefsAsMask);
23878 SmallBitVector IsFirstUndef =
23880 if ((!IsIdentity ||
Offset != 0 || !IsFirstUndef.
all()) &&
23881 NumElts != NumScalars) {
23882 if (IsFirstUndef.
all()) {
23884 SmallBitVector IsFirstPoison =
23886 if (!IsFirstPoison.
all()) {
23887 for (
unsigned I = 0;
I < NumElts;
I++) {
23889 InsertMask[
I] =
I + NumElts;
23892 V = Builder.CreateShuffleVector(
23898 GatherShuffleExtractSeq.insert(
I);
23899 CSEBlocks.insert(
I->getParent());
23903 SmallBitVector IsFirstPoison =
23905 for (
unsigned I = 0;
I < NumElts;
I++) {
23909 InsertMask[
I] += NumElts;
23911 V = Builder.CreateShuffleVector(
23912 FirstInsert->getOperand(0), V, InsertMask,
23915 GatherShuffleExtractSeq.insert(
I);
23916 CSEBlocks.insert(
I->getParent());
23921 ++NumVectorInstructions;
23922 if (ShuffleOrOp == Instruction::InsertValue &&
23924 Type *AggTy =
E->getMainOp()->getType();
23925 Align SlotAlign = std::max(DL->getPrefTypeAlign(
V->getType()),
23926 DL->getPrefTypeAlign(AggTy));
23931 IRBuilderBase::InsertPointGuard Guard(Builder);
23932 Builder.SetInsertPointPastAllocas(F);
23933 Slot = Builder.CreateAlloca(AggTy,
nullptr,
23934 "vec2struct.slot");
23935 Slot->setAlignment(SlotAlign);
23937 (void)Builder.CreateAlignedStore(V, Slot, SlotAlign);
23938 V = Builder.CreateAlignedLoad(AggTy, Slot, SlotAlign,
"vec2struct");
23939 NumVectorInstructions += 2;
23941 E->VectorizedValue =
V;
23944 case Instruction::ZExt:
23945 case Instruction::SExt:
23946 case Instruction::FPToUI:
23947 case Instruction::FPToSI:
23948 case Instruction::FPExt:
23949 case Instruction::PtrToInt:
23950 case Instruction::PtrToAddr:
23951 case Instruction::IntToPtr:
23952 case Instruction::SIToFP:
23953 case Instruction::UIToFP:
23954 case Instruction::Trunc:
23955 case Instruction::FPTrunc:
23956 case Instruction::BitCast: {
23957 setInsertPointAfterBundle(
E);
23959 Value *InVec = vectorizeOperand(
E, 0);
23964 auto SrcIt = MinBWs.find(getOperandEntry(
E, 0));
23966 (SrcIt != MinBWs.end() || It != MinBWs.end() ||
23969 unsigned SrcBWSz = DL->getTypeSizeInBits(SrcScalarTy);
23970 if (SrcIt != MinBWs.end())
23971 SrcBWSz = SrcIt->second.first;
23972 unsigned BWSz = DL->getTypeSizeInBits(ScalarTy->
getScalarType());
23973 if (BWSz == SrcBWSz) {
23974 VecOpcode = Instruction::BitCast;
23975 }
else if (BWSz < SrcBWSz) {
23976 VecOpcode = Instruction::Trunc;
23977 }
else if (It != MinBWs.end()) {
23978 assert(BWSz > SrcBWSz &&
"Invalid cast!");
23979 VecOpcode = It->second.second ? Instruction::SExt : Instruction::ZExt;
23980 }
else if (SrcIt != MinBWs.end()) {
23981 assert(BWSz > SrcBWSz &&
"Invalid cast!");
23983 SrcIt->second.second ? Instruction::SExt : Instruction::ZExt;
23985 }
else if (VecOpcode == Instruction::SIToFP && SrcIt != MinBWs.end() &&
23986 !SrcIt->second.second) {
23987 VecOpcode = Instruction::UIToFP;
23988 }
else if (VecOpcode == Instruction::BitCast && SrcIt != MinBWs.end() &&
23990 Type *OrigSrcScalarTy = CI->getSrcTy();
23991 auto *OrigSrcVectorTy =
23994 Builder.CreateIntCast(InVec, OrigSrcVectorTy, SrcIt->second.second);
23996 Value *
V = (VecOpcode != ShuffleOrOp && VecOpcode == Instruction::BitCast)
23998 : Builder.CreateCast(VecOpcode, InVec, VecTy);
23999 V = FinalShuffle(V,
E);
24001 E->VectorizedValue =
V;
24002 ++NumVectorInstructions;
24005 case Instruction::FCmp:
24006 case Instruction::ICmp: {
24007 setInsertPointAfterBundle(
E);
24009 Value *
L = vectorizeOperand(
E, 0);
24010 Value *
R = vectorizeOperand(
E, 1);
24011 if (
L->getType() !=
R->getType()) {
24014 MinBWs.contains(getOperandEntry(
E, 0)) ||
24015 MinBWs.contains(getOperandEntry(
E, 1))) &&
24016 "Expected item in MinBWs.");
24019 ->getIntegerBitWidth();
24022 ->getIntegerBitWidth();
24025 auto GetRequiredBits = [
Signed](
const APInt &
V) {
24026 return Signed ?
V.getSignificantBits() :
V.getActiveBits();
24032 auto *CI = dyn_cast<ConstantInt>(V);
24034 GetRequiredBits(CI->getValue()) > LBW;
24038 auto *CI = dyn_cast<ConstantInt>(V);
24039 return CI && GetRequiredBits(CI->getValue()) <= RBW;
24041 Type *CastTy =
R->getType();
24042 L = Builder.CreateIntCast(L, CastTy, GetOperandSignedness(0));
24044 Type *CastTy =
L->getType();
24045 R = Builder.CreateIntCast(R, CastTy, GetOperandSignedness(1));
24060 if (OrigOpTy &&
L->getType() ==
R->getType() &&
24061 LTy->getElementType()->getIntegerBitWidth() <
24062 OrigOpTy->getBitWidth()) {
24063 bool IsSigned0 = GetOperandSignedness(0);
24064 bool IsSigned1 = GetOperandSignedness(1);
24068 if (ICmpInst::isSigned(P0))
24069 KeepNarrowTy = (IsSigned0 || NonNeg0) && (IsSigned1 || NonNeg1);
24070 else if (ICmpInst::isUnsigned(P0))
24071 KeepNarrowTy = (!IsSigned0 || NonNeg0) && (!IsSigned1 || NonNeg1);
24073 KeepNarrowTy = IsSigned0 == IsSigned1 || NonNeg0 || NonNeg1;
24074 if (!KeepNarrowTy) {
24076 L = Builder.CreateIntCast(L, CastTy, IsSigned0);
24077 R = Builder.CreateIntCast(R, CastTy, IsSigned1);
24081 Value *
V = Builder.CreateCmp(P0, L, R);
24082 V = PropagateIRFlags(V);
24085 V = FinalShuffle(V,
E);
24087 E->VectorizedValue =
V;
24088 ++NumVectorInstructions;
24091 case Instruction::Select: {
24092 setInsertPointAfterBundle(
E);
24095 Value *True = vectorizeOperand(
E, 1);
24096 Value *False = vectorizeOperand(
E, 2);
24100 MinBWs.contains(getOperandEntry(
E, 1)) ||
24101 MinBWs.contains(getOperandEntry(
E, 2))) &&
24102 "Expected item in MinBWs.");
24103 if (True->
getType() != VecTy)
24104 True = Builder.CreateIntCast(True, VecTy, GetOperandSignedness(1));
24105 if (False->
getType() != VecTy)
24106 False = Builder.CreateIntCast(False, VecTy, GetOperandSignedness(2));
24111 assert(TrueNumElements >= CondNumElements &&
24112 TrueNumElements % CondNumElements == 0 &&
24113 "Cannot vectorize Instruction::Select");
24115 "Cannot vectorize Instruction::Select");
24116 if (CondNumElements != TrueNumElements) {
24119 Cond = Builder.CreateShuffleVector(
24124 "Cannot vectorize Instruction::Select");
24126 Builder.CreateSelectWithUnknownProfile(
Cond, True, False,
DEBUG_TYPE);
24127 V = FinalShuffle(V,
E);
24129 E->VectorizedValue =
V;
24130 ++NumVectorInstructions;
24133 case Instruction::FNeg: {
24134 setInsertPointAfterBundle(
E);
24136 Value *
Op = vectorizeOperand(
E, 0);
24138 Value *
V = Builder.CreateUnOp(
24140 V = PropagateIRFlags(V);
24142 V = FinalShuffle(V,
E);
24144 E->VectorizedValue =
V;
24145 ++NumVectorInstructions;
24149 case Instruction::Freeze: {
24150 setInsertPointAfterBundle(
E);
24152 Value *
Op = vectorizeOperand(
E, 0);
24154 if (
Op->getType() != VecTy) {
24156 MinBWs.contains(getOperandEntry(
E, 0))) &&
24157 "Expected item in MinBWs.");
24158 Op = Builder.CreateIntCast(
Op, VecTy, GetOperandSignedness(0));
24160 Value *
V = Builder.CreateFreeze(
Op);
24161 V = FinalShuffle(V,
E);
24163 E->VectorizedValue =
V;
24164 ++NumVectorInstructions;
24168 case Instruction::Add:
24169 case Instruction::FAdd:
24170 case Instruction::Sub:
24171 case Instruction::FSub:
24172 case Instruction::Mul:
24173 case Instruction::FMul:
24174 case Instruction::UDiv:
24175 case Instruction::SDiv:
24176 case Instruction::FDiv:
24177 case Instruction::URem:
24178 case Instruction::SRem:
24179 case Instruction::FRem:
24180 case Instruction::Shl:
24181 case Instruction::LShr:
24182 case Instruction::AShr:
24183 case Instruction::And:
24184 case Instruction::Or:
24185 case Instruction::Xor: {
24186 setInsertPointAfterBundle(
E);
24188 if (
E->hasReassocScalars()) {