Skip to content

Commit 8796dfd

Browse files
committed
[VPlan] Consolidate logic to update loop metadata and profile info.
This patch consolidates updating loop metadata and profile info for both the remainder and vector loops in a single place. This is NFC, modulo consistently applying vectorization specific metadata also in the experimental VPlan-native path. Split off from #154510.
1 parent 0e73ebc commit 8796dfd

File tree

5 files changed

+157
-144
lines changed

5 files changed

+157
-144
lines changed

llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,15 @@ class LoopVectorizationPlanner {
568568
void addMinimumIterationCheck(VPlan &Plan, ElementCount VF, unsigned UF,
569569
ElementCount MinProfitableTripCount) const;
570570

571+
/// Update loop metadata and profile info for both the scalar remainder loop
572+
/// and \p VectorLoop, if it exists. Keeps all loop hints from the original
573+
/// loop on the vector loop and replaces vectorizer-specific metadata.
574+
void updateLoopMetadataAndProfileInfo(Loop *VectorLoop,
575+
VPBasicBlock *HeaderVPBB,
576+
bool VectorizingEpilogue,
577+
unsigned EstimatedVFxUF,
578+
bool DisableRuntimeUnroll);
579+
571580
protected:
572581
/// Build VPlans for power-of-2 VF's between \p MinVF and \p MaxVF inclusive,
573582
/// according to the information gathered by Legal when it checked if it is

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 11 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,6 @@ using namespace SCEVPatternMatch;
165165
const char VerboseDebug[] = DEBUG_TYPE "-verbose";
166166
#endif
167167

168-
/// @{
169-
/// Metadata attribute names
170-
const char LLVMLoopVectorizeFollowupAll[] = "llvm.loop.vectorize.followup_all";
171-
const char LLVMLoopVectorizeFollowupVectorized[] =
172-
"llvm.loop.vectorize.followup_vectorized";
173-
const char LLVMLoopVectorizeFollowupEpilogue[] =
174-
"llvm.loop.vectorize.followup_epilogue";
175-
/// @}
176-
177168
STATISTIC(LoopsVectorized, "Number of loops vectorized");
178169
STATISTIC(LoopsAnalyzed, "Number of loops analyzed for vectorization");
179170
STATISTIC(LoopsEpilogueVectorized, "Number of epilogues vectorized");
@@ -2569,24 +2560,6 @@ void InnerLoopVectorizer::fixVectorizedLoop(VPTransformState &State) {
25692560

25702561
// Remove redundant induction instructions.
25712562
cse(HeaderBB);
2572-
2573-
// Set/update profile weights for the vector and remainder loops as original
2574-
// loop iterations are now distributed among them. Note that original loop
2575-
// becomes the scalar remainder loop after vectorization.
2576-
//
2577-
// For cases like foldTailByMasking() and requiresScalarEpiloque() we may
2578-
// end up getting slightly roughened result but that should be OK since
2579-
// profile is not inherently precise anyway. Note also possible bypass of
2580-
// vector code caused by legality checks is ignored, assigning all the weight
2581-
// to the vector loop, optimistically.
2582-
//
2583-
// For scalable vectorization we can't know at compile time how many
2584-
// iterations of the loop are handled in one vector iteration, so instead
2585-
// use the value of vscale used for tuning.
2586-
Loop *VectorLoop = LI->getLoopFor(HeaderBB);
2587-
unsigned EstimatedVFxUF =
2588-
estimateElementCount(VF * UF, Cost->getVScaleForTuning());
2589-
setProfileInfoAfterUnrolling(OrigLoop, VectorLoop, OrigLoop, EstimatedVFxUF);
25902563
}
25912564

25922565
void InnerLoopVectorizer::fixNonInductionPHIs(VPTransformState &State) {
@@ -7098,40 +7071,6 @@ VectorizationFactor LoopVectorizationPlanner::computeBestVF() {
70987071
return BestFactor;
70997072
}
71007073

7101-
static void addRuntimeUnrollDisableMetaData(Loop *L) {
7102-
SmallVector<Metadata *, 4> MDs;
7103-
// Reserve first location for self reference to the LoopID metadata node.
7104-
MDs.push_back(nullptr);
7105-
bool IsUnrollMetadata = false;
7106-
MDNode *LoopID = L->getLoopID();
7107-
if (LoopID) {
7108-
// First find existing loop unrolling disable metadata.
7109-
for (unsigned I = 1, IE = LoopID->getNumOperands(); I < IE; ++I) {
7110-
auto *MD = dyn_cast<MDNode>(LoopID->getOperand(I));
7111-
if (MD) {
7112-
const auto *S = dyn_cast<MDString>(MD->getOperand(0));
7113-
IsUnrollMetadata =
7114-
S && S->getString().starts_with("llvm.loop.unroll.disable");
7115-
}
7116-
MDs.push_back(LoopID->getOperand(I));
7117-
}
7118-
}
7119-
7120-
if (!IsUnrollMetadata) {
7121-
// Add runtime unroll disable metadata.
7122-
LLVMContext &Context = L->getHeader()->getContext();
7123-
SmallVector<Metadata *, 1> DisableOperands;
7124-
DisableOperands.push_back(
7125-
MDString::get(Context, "llvm.loop.unroll.runtime.disable"));
7126-
MDNode *DisableNode = MDNode::get(Context, DisableOperands);
7127-
MDs.push_back(DisableNode);
7128-
MDNode *NewLoopID = MDNode::get(Context, MDs);
7129-
// Set operand 0 to refer to the loop id itself.
7130-
NewLoopID->replaceOperandWith(0, NewLoopID);
7131-
L->setLoopID(NewLoopID);
7132-
}
7133-
}
7134-
71357074
static Value *getStartValueFromReductionResult(VPInstruction *RdxResult) {
71367075
using namespace VPlanPatternMatch;
71377076
assert(RdxResult->getOpcode() == VPInstruction::ComputeFindIVResult &&
@@ -7316,50 +7255,16 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
73167255
// Keep all loop hints from the original loop on the vector loop (we'll
73177256
// replace the vectorizer-specific hints below).
73187257
VPBasicBlock *HeaderVPBB = vputils::getFirstLoopHeader(BestVPlan, State.VPDT);
7319-
if (HeaderVPBB) {
7320-
MDNode *OrigLoopID = OrigLoop->getLoopID();
7321-
7322-
std::optional<MDNode *> VectorizedLoopID =
7323-
makeFollowupLoopID(OrigLoopID, {LLVMLoopVectorizeFollowupAll,
7324-
LLVMLoopVectorizeFollowupVectorized});
7325-
7326-
Loop *L = LI->getLoopFor(State.CFG.VPBB2IRBB[HeaderVPBB]);
7327-
if (VectorizedLoopID) {
7328-
L->setLoopID(*VectorizedLoopID);
7329-
} else {
7330-
// Keep all loop hints from the original loop on the vector loop (we'll
7331-
// replace the vectorizer-specific hints below).
7332-
if (MDNode *LID = OrigLoop->getLoopID())
7333-
L->setLoopID(LID);
7334-
7335-
LoopVectorizeHints Hints(L, true, *ORE);
7336-
Hints.setAlreadyVectorized();
7337-
7338-
// Check if it's EVL-vectorized and mark the corresponding metadata.
7339-
bool IsEVLVectorized =
7340-
llvm::any_of(*HeaderVPBB, [](const VPRecipeBase &Recipe) {
7341-
// Looking for the ExplictVectorLength VPInstruction.
7342-
if (const auto *VI = dyn_cast<VPInstruction>(&Recipe))
7343-
return VI->getOpcode() == VPInstruction::ExplicitVectorLength;
7344-
return false;
7345-
});
7346-
if (IsEVLVectorized) {
7347-
LLVMContext &Context = L->getHeader()->getContext();
7348-
MDNode *LoopID = L->getLoopID();
7349-
auto *IsEVLVectorizedMD = MDNode::get(
7350-
Context,
7351-
{MDString::get(Context, "llvm.loop.isvectorized.tailfoldingstyle"),
7352-
MDString::get(Context, "evl")});
7353-
MDNode *NewLoopID = makePostTransformationMetadata(Context, LoopID, {},
7354-
{IsEVLVectorizedMD});
7355-
L->setLoopID(NewLoopID);
7356-
}
7357-
}
7358-
TargetTransformInfo::UnrollingPreferences UP;
7359-
TTI.getUnrollingPreferences(L, *PSE.getSE(), UP, ORE);
7360-
if (!UP.UnrollVectorizedLoop || VectorizingEpilogue)
7361-
addRuntimeUnrollDisableMetaData(L);
7362-
}
7258+
// Add metadata to disable runtime unrolling a scalar loop when there
7259+
// are no runtime checks about strides and memory. A scalar loop that is
7260+
// rarely used is not worth unrolling.
7261+
bool DisableRuntimeUnroll = !ILV.RTChecks.hasChecks() && !BestVF.isScalar();
7262+
updateLoopMetadataAndProfileInfo(
7263+
HeaderVPBB ? LI->getLoopFor(State.CFG.VPBB2IRBB.lookup(HeaderVPBB))
7264+
: nullptr,
7265+
HeaderVPBB, VectorizingEpilogue,
7266+
estimateElementCount(BestVF * BestUF, CM.getVScaleForTuning()),
7267+
DisableRuntimeUnroll);
73637268

73647269
// 3. Fix the vectorized code: take care of header phi's, live-outs,
73657270
// predication, updating analyses.
@@ -9377,8 +9282,6 @@ static bool processLoopInVPlanNativePath(
93779282

93789283
reportVectorization(ORE, L, VF, 1);
93799284

9380-
// Mark the loop as already vectorized to avoid vectorizing again.
9381-
Hints.setAlreadyVectorized();
93829285
assert(!verifyFunction(*L->getHeader()->getParent(), &dbgs()));
93839286
return true;
93849287
}
@@ -10191,9 +10094,6 @@ bool LoopVectorizePass::processLoop(Loop *L) {
1019110094
LLVM_DEBUG(dbgs() << "LV: Interleave Count is " << IC << '\n');
1019210095
}
1019310096

10194-
bool DisableRuntimeUnroll = false;
10195-
MDNode *OrigLoopID = L->getLoopID();
10196-
1019710097
// Report the vectorization decision.
1019810098
if (VF.Width.isScalar()) {
1019910099
using namespace ore;
@@ -10249,9 +10149,6 @@ bool LoopVectorizePass::processLoop(Loop *L) {
1024910149
BestEpiPlan, LVL, ExpandedSCEVs,
1025010150
EPI.VectorTripCount);
1025110151
++LoopsEpilogueVectorized;
10252-
10253-
if (!Checks.hasChecks())
10254-
DisableRuntimeUnroll = true;
1025510152
} else {
1025610153
InnerLoopVectorizer LB(L, PSE, LI, DT, TTI, AC, VF.Width, IC, &CM, BFI, PSI,
1025710154
Checks, BestPlan);
@@ -10265,31 +10162,12 @@ bool LoopVectorizePass::processLoop(Loop *L) {
1026510162

1026610163
LVP.executePlan(VF.Width, IC, BestPlan, LB, DT, false);
1026710164
++LoopsVectorized;
10268-
10269-
// Add metadata to disable runtime unrolling a scalar loop when there
10270-
// are no runtime checks about strides and memory. A scalar loop that is
10271-
// rarely used is not worth unrolling.
10272-
if (!Checks.hasChecks() && !VF.Width.isScalar())
10273-
DisableRuntimeUnroll = true;
1027410165
}
1027510166

1027610167
assert(DT->verify(DominatorTree::VerificationLevel::Fast) &&
1027710168
"DT not preserved correctly");
10169+
assert(!verifyFunction(*F, &dbgs()));
1027810170

10279-
std::optional<MDNode *> RemainderLoopID =
10280-
makeFollowupLoopID(OrigLoopID, {LLVMLoopVectorizeFollowupAll,
10281-
LLVMLoopVectorizeFollowupEpilogue});
10282-
if (RemainderLoopID) {
10283-
L->setLoopID(*RemainderLoopID);
10284-
} else {
10285-
if (DisableRuntimeUnroll)
10286-
addRuntimeUnrollDisableMetaData(L);
10287-
10288-
// Mark the loop as already vectorized to avoid vectorizing again.
10289-
Hints.setAlreadyVectorized();
10290-
}
10291-
10292-
assert(!verifyFunction(*L->getHeader()->getParent(), &dbgs()));
1029310171
return true;
1029410172
}
1029510173

llvm/lib/Transforms/Vectorize/VPlan.cpp

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "llvm/Support/raw_ostream.h"
4646
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
4747
#include "llvm/Transforms/Utils/LoopVersioning.h"
48+
#include "llvm/Transforms/Vectorize/LoopVectorizationLegality.h"
4849
#include <cassert>
4950
#include <string>
5051

@@ -55,6 +56,15 @@ namespace llvm {
5556
extern cl::opt<bool> EnableVPlanNativePath;
5657
}
5758

59+
/// @{
60+
/// Metadata attribute names
61+
const char LLVMLoopVectorizeFollowupAll[] = "llvm.loop.vectorize.followup_all";
62+
const char LLVMLoopVectorizeFollowupVectorized[] =
63+
"llvm.loop.vectorize.followup_vectorized";
64+
const char LLVMLoopVectorizeFollowupEpilogue[] =
65+
"llvm.loop.vectorize.followup_epilogue";
66+
/// @}
67+
5868
extern cl::opt<unsigned> ForceTargetInstructionCost;
5969

6070
static cl::opt<bool> PrintVPlansInDotFormat(
@@ -1615,6 +1625,123 @@ VPlan &LoopVectorizationPlanner::getPlanFor(ElementCount VF) const {
16151625
llvm_unreachable("No plan found!");
16161626
}
16171627

1628+
static void addRuntimeUnrollDisableMetaData(Loop *L) {
1629+
SmallVector<Metadata *, 4> MDs;
1630+
// Reserve first location for self reference to the LoopID metadata node.
1631+
MDs.push_back(nullptr);
1632+
bool IsUnrollMetadata = false;
1633+
MDNode *LoopID = L->getLoopID();
1634+
if (LoopID) {
1635+
// First find existing loop unrolling disable metadata.
1636+
for (unsigned I = 1, IE = LoopID->getNumOperands(); I < IE; ++I) {
1637+
auto *MD = dyn_cast<MDNode>(LoopID->getOperand(I));
1638+
if (MD) {
1639+
const auto *S = dyn_cast<MDString>(MD->getOperand(0));
1640+
if (!S)
1641+
continue;
1642+
if (S->getString().starts_with("llvm.loop.unroll.runtime.disable"))
1643+
continue;
1644+
IsUnrollMetadata =
1645+
S->getString().starts_with("llvm.loop.unroll.disable");
1646+
}
1647+
MDs.push_back(LoopID->getOperand(I));
1648+
}
1649+
}
1650+
1651+
if (!IsUnrollMetadata) {
1652+
// Add runtime unroll disable metadata.
1653+
LLVMContext &Context = L->getHeader()->getContext();
1654+
SmallVector<Metadata *, 1> DisableOperands;
1655+
DisableOperands.push_back(
1656+
MDString::get(Context, "llvm.loop.unroll.runtime.disable"));
1657+
MDNode *DisableNode = MDNode::get(Context, DisableOperands);
1658+
MDs.push_back(DisableNode);
1659+
MDNode *NewLoopID = MDNode::get(Context, MDs);
1660+
// Set operand 0 to refer to the loop id itself.
1661+
NewLoopID->replaceOperandWith(0, NewLoopID);
1662+
L->setLoopID(NewLoopID);
1663+
}
1664+
}
1665+
1666+
void LoopVectorizationPlanner::updateLoopMetadataAndProfileInfo(
1667+
Loop *VectorLoop, VPBasicBlock *HeaderVPBB, bool VectorizingEpilogue,
1668+
unsigned EstimatedVFxUF, bool DisableRuntimeUnroll) {
1669+
MDNode *LID = OrigLoop->getLoopID();
1670+
// Update the metadata of the scalar loop. Skip the update when vectorizing
1671+
// the epilogue loop, to ensure it is only updated once.
1672+
if (!VectorizingEpilogue) {
1673+
std::optional<MDNode *> RemainderLoopID = makeFollowupLoopID(
1674+
LID, {LLVMLoopVectorizeFollowupAll, LLVMLoopVectorizeFollowupEpilogue});
1675+
if (RemainderLoopID) {
1676+
OrigLoop->setLoopID(*RemainderLoopID);
1677+
} else {
1678+
if (DisableRuntimeUnroll)
1679+
addRuntimeUnrollDisableMetaData(OrigLoop);
1680+
1681+
LoopVectorizeHints Hints(OrigLoop, true, *ORE);
1682+
Hints.setAlreadyVectorized();
1683+
}
1684+
}
1685+
1686+
if (!VectorLoop)
1687+
return;
1688+
1689+
if (std::optional<MDNode *> VectorizedLoopID =
1690+
makeFollowupLoopID(LID, {LLVMLoopVectorizeFollowupAll,
1691+
LLVMLoopVectorizeFollowupVectorized})) {
1692+
VectorLoop->setLoopID(*VectorizedLoopID);
1693+
} else {
1694+
// Keep all loop hints from the original loop on the vector loop (we'll
1695+
// replace the vectorizer-specific hints below).
1696+
if (LID)
1697+
VectorLoop->setLoopID(LID);
1698+
1699+
if (!VectorizingEpilogue) {
1700+
LoopVectorizeHints Hints(VectorLoop, true, *ORE);
1701+
Hints.setAlreadyVectorized();
1702+
}
1703+
1704+
// Check if it's EVL-vectorized and mark the corresponding metadata.
1705+
bool IsEVLVectorized =
1706+
llvm::any_of(*HeaderVPBB, [](const VPRecipeBase &Recipe) {
1707+
// Looking for the ExplictVectorLength VPInstruction.
1708+
if (const auto *VI = dyn_cast<VPInstruction>(&Recipe))
1709+
return VI->getOpcode() == VPInstruction::ExplicitVectorLength;
1710+
return false;
1711+
});
1712+
if (IsEVLVectorized) {
1713+
LLVMContext &Context = VectorLoop->getHeader()->getContext();
1714+
MDNode *LoopID = VectorLoop->getLoopID();
1715+
auto *IsEVLVectorizedMD = MDNode::get(
1716+
Context,
1717+
{MDString::get(Context, "llvm.loop.isvectorized.tailfoldingstyle"),
1718+
MDString::get(Context, "evl")});
1719+
MDNode *NewLoopID = makePostTransformationMetadata(Context, LoopID, {},
1720+
{IsEVLVectorizedMD});
1721+
VectorLoop->setLoopID(NewLoopID);
1722+
}
1723+
}
1724+
TargetTransformInfo::UnrollingPreferences UP;
1725+
TTI.getUnrollingPreferences(VectorLoop, *PSE.getSE(), UP, ORE);
1726+
if (!UP.UnrollVectorizedLoop || VectorizingEpilogue)
1727+
addRuntimeUnrollDisableMetaData(VectorLoop);
1728+
1729+
// Set/update profile weights for the vector and remainder loops as original
1730+
// loop iterations are now distributed among them. Note that original loop
1731+
// becomes the scalar remainder loop after vectorization.
1732+
//
1733+
// For cases like foldTailByMasking() and requiresScalarEpiloque() we may
1734+
// end up getting slightly roughened result but that should be OK since
1735+
// profile is not inherently precise anyway. Note also possible bypass of
1736+
// vector code caused by legality checks is ignored, assigning all the weight
1737+
// to the vector loop, optimistically.
1738+
//
1739+
// For scalable vectorization we can't know at compile time how many
1740+
// iterations of the loop are handled in one vector iteration, so instead
1741+
// use the value of vscale used for tuning.
1742+
setProfileInfoAfterUnrolling(OrigLoop, VectorLoop, OrigLoop, EstimatedVFxUF);
1743+
}
1744+
16181745
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
16191746
void LoopVectorizationPlanner::printPlans(raw_ostream &O) {
16201747
if (VPlans.empty()) {

0 commit comments

Comments
 (0)