-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[VPlan] Add helper to run VPlan passes, verify after run (NFC). #123640
Conversation
@llvm/pr-subscribers-vectorizers @llvm/pr-subscribers-llvm-transforms Author: Florian Hahn (fhahn) ChangesAdd new runPass helpers to run a VPlan transformation. This makes it easier to add additional checks/functionality for each transform run. In this patch, an option is added to run the verifier after each VPlan transform. Follow-ups will use the same helper to also support printing VPlans after each transform. Note that the verifier at the moment requires there to be a canonical IV and vector loop region, so the final lowering transforms aren't run via runPass yet. Full diff: https://github.com/llvm/llvm-project/pull/123640.diff 4 Files Affected:
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 29f3940ed6fa7a..8f101814d71503 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -355,6 +355,16 @@ cl::opt<bool> EnableVPlanNativePath(
"enable-vplan-native-path", cl::Hidden,
cl::desc("Enable VPlan-native vectorization path with "
"support for outer loop vectorization."));
+
+cl::opt<bool>
+ VerifyEachVPlan("vplan-verify-each",
+#ifdef EXPENSIVE_CHECKS
+ cl::init(true),
+#else
+ cl::init(false),
+#endif
+ cl::Hidden,
+ cl::desc("Verfiy VPlans after VPlan transforms."));
} // namespace llvm
// This flag enables the stress testing of the VPlan H-CFG construction in the
@@ -7649,8 +7659,8 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
// TODO: Move to VPlan transform stage once the transition to the VPlan-based
// cost model is complete for better cost estimates.
- VPlanTransforms::unrollByUF(BestVPlan, BestUF,
- OrigLoop->getHeader()->getContext());
+ VPlanTransforms::runPass(VPlanTransforms::unrollByUF, BestVPlan, BestUF,
+ OrigLoop->getHeader()->getContext());
VPlanTransforms::optimizeForVFAndUF(BestVPlan, BestVF, BestUF, PSE);
VPlanTransforms::convertToConcreteRecipes(BestVPlan);
@@ -8887,13 +8897,14 @@ void LoopVectorizationPlanner::buildVPlansWithVPRecipes(ElementCount MinVF,
if (auto Plan = tryToBuildVPlanWithVPRecipes(SubRange)) {
// Now optimize the initial VPlan.
if (!Plan->hasVF(ElementCount::getFixed(1)))
- VPlanTransforms::truncateToMinimalBitwidths(*Plan,
- CM.getMinimalBitwidths());
+ VPlanTransforms::runPass(VPlanTransforms::truncateToMinimalBitwidths,
+ *Plan, CM.getMinimalBitwidths());
VPlanTransforms::optimize(*Plan);
// TODO: try to put it close to addActiveLaneMask().
// Discard the plan if it is not EVL-compatible
- if (CM.foldTailWithEVL() && !VPlanTransforms::tryAddExplicitVectorLength(
- *Plan, CM.getMaxSafeElements()))
+ if (CM.foldTailWithEVL() &&
+ !VPlanTransforms::runPass(VPlanTransforms::tryAddExplicitVectorLength,
+ *Plan, CM.getMaxSafeElements()))
break;
assert(verifyVPlanIsValid(*Plan) && "VPlan is invalid");
VPlans.push_back(std::move(Plan));
@@ -9393,8 +9404,9 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
if (auto *UncountableExitingBlock =
Legal->getUncountableEarlyExitingBlock()) {
- VPlanTransforms::handleUncountableEarlyExit(
- *Plan, *PSE.getSE(), OrigLoop, UncountableExitingBlock, RecipeBuilder);
+ VPlanTransforms::runPass(VPlanTransforms::handleUncountableEarlyExit, *Plan,
+ *PSE.getSE(), OrigLoop, UncountableExitingBlock,
+ RecipeBuilder);
}
DenseMap<VPValue *, VPValue *> IVEndValues;
addScalarResumePhis(RecipeBuilder, *Plan, IVEndValues);
@@ -9419,8 +9431,9 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
// Interleave memory: for each Interleave Group we marked earlier as relevant
// for this VPlan, replace the Recipes widening its memory instructions with a
// single VPInterleaveRecipe at its insertion point.
- VPlanTransforms::createInterleaveGroups(
- *Plan, InterleaveGroups, RecipeBuilder, CM.isScalarEpilogueAllowed());
+ VPlanTransforms::runPass(VPlanTransforms::createInterleaveGroups, *Plan,
+ InterleaveGroups, RecipeBuilder,
+ CM.isScalarEpilogueAllowed());
for (ElementCount VF : Range)
Plan->addVF(VF);
@@ -9462,13 +9475,16 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
}
}
- VPlanTransforms::dropPoisonGeneratingRecipes(*Plan, [this](BasicBlock *BB) {
+ auto BlockNeedsPredication = [this](BasicBlock *BB) {
return Legal->blockNeedsPredication(BB);
- });
+ };
+ VPlanTransforms::runPass(VPlanTransforms::dropPoisonGeneratingRecipes, *Plan,
+ BlockNeedsPredication);
// Sink users of fixed-order recurrence past the recipe defining the previous
// value and introduce FirstOrderRecurrenceSplice VPInstructions.
- if (!VPlanTransforms::adjustFixedOrderRecurrences(*Plan, Builder))
+ if (!VPlanTransforms::runPass(VPlanTransforms::adjustFixedOrderRecurrences,
+ *Plan, Builder))
return nullptr;
if (useActiveLaneMask(Style)) {
@@ -9817,10 +9833,10 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(
PhiR->setOperand(0, Plan->getOrAddLiveIn(RdxDesc.getSentinelValue()));
}
}
-
- VPlanTransforms::clearReductionWrapFlags(*Plan);
for (VPRecipeBase *R : ToDelete)
R->eraseFromParent();
+
+ VPlanTransforms::runPass(VPlanTransforms::clearReductionWrapFlags, *Plan);
}
void VPDerivedIVRecipe::execute(VPTransformState &State) {
@@ -10184,7 +10200,7 @@ static void preparePlanForMainVectorLoop(VPlan &MainPlan, VPlan &EpiPlan) {
VPIRInst->eraseFromParent();
ResumePhi->eraseFromParent();
}
- VPlanTransforms::removeDeadRecipes(MainPlan);
+ VPlanTransforms::runPass(VPlanTransforms::removeDeadRecipes, MainPlan);
using namespace VPlanPatternMatch;
VPBasicBlock *MainScalarPH = MainPlan.getScalarPreheader();
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index f1228368804beb..4081cf87cdc199 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -52,6 +52,7 @@ using namespace llvm::VPlanPatternMatch;
namespace llvm {
extern cl::opt<bool> EnableVPlanNativePath;
}
+
extern cl::opt<unsigned> ForceTargetInstructionCost;
static cl::opt<bool> PrintVPlansInDotFormat(
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 9febd612c644e1..4da2b0f8bf6961 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -19,6 +19,7 @@
#include "VPlanDominatorTree.h"
#include "VPlanPatternMatch.h"
#include "VPlanUtils.h"
+#include "VPlanVerifier.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
@@ -1439,19 +1440,19 @@ void VPlanTransforms::truncateToMinimalBitwidths(
}
void VPlanTransforms::optimize(VPlan &Plan) {
- removeRedundantCanonicalIVs(Plan);
- removeRedundantInductionCasts(Plan);
+ runPass(removeRedundantCanonicalIVs, Plan);
+ runPass(removeRedundantInductionCasts, Plan);
simplifyRecipes(Plan, Plan.getCanonicalIV()->getScalarType());
- removeDeadRecipes(Plan);
- legalizeAndOptimizeInductions(Plan);
- removeRedundantExpandSCEVRecipes(Plan);
+ runPass(removeDeadRecipes, Plan);
+ runPass(legalizeAndOptimizeInductions, Plan);
+ runPass(removeRedundantExpandSCEVRecipes, Plan);
simplifyRecipes(Plan, Plan.getCanonicalIV()->getScalarType());
- removeDeadRecipes(Plan);
+ runPass(removeDeadRecipes, Plan);
- createAndOptimizeReplicateRegions(Plan);
- mergeBlocksIntoPredecessors(Plan);
- licm(Plan);
+ runPass(createAndOptimizeReplicateRegions, Plan);
+ runPass(mergeBlocksIntoPredecessors, Plan);
+ runPass(licm, Plan);
}
// Add a VPActiveLaneMaskPHIRecipe and related recipes to \p Plan and replace
@@ -1871,7 +1872,8 @@ bool VPlanTransforms::tryAddExplicitVectorLength(
}
void VPlanTransforms::dropPoisonGeneratingRecipes(
- VPlan &Plan, function_ref<bool(BasicBlock *)> BlockNeedsPredication) {
+ VPlan &Plan,
+ const std::function<bool(BasicBlock *)> &BlockNeedsPredication) {
// Collect recipes in the backward slice of `Root` that may generate a poison
// value that is used after vectorization.
SmallPtrSet<VPRecipeBase *, 16> Visited;
@@ -1971,7 +1973,7 @@ void VPlanTransforms::createInterleaveGroups(
VPlan &Plan,
const SmallPtrSetImpl<const InterleaveGroup<Instruction> *>
&InterleaveGroups,
- VPRecipeBuilder &RecipeBuilder, bool ScalarEpilogueAllowed) {
+ VPRecipeBuilder &RecipeBuilder, const bool &ScalarEpilogueAllowed) {
if (InterleaveGroups.empty())
return;
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
index a751b8b5e8dc59..0cd4cf1f22a7db 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
@@ -14,7 +14,9 @@
#define LLVM_TRANSFORMS_VECTORIZE_VPLANTRANSFORMS_H
#include "VPlan.h"
+#include "VPlanVerifier.h"
#include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/Support/CommandLine.h"
namespace llvm {
@@ -27,7 +29,29 @@ class TargetLibraryInfo;
class VPBuilder;
class VPRecipeBuilder;
+extern cl::opt<bool> VerifyEachVPlan;
+
struct VPlanTransforms {
+ /// Helper to run a VPlan transform \p Transform on \p VPlan, forwarding extra
+ /// arguments to the transform. Returns the boolean returned by the transform.
+ template <typename... ArgsTy>
+ static bool runPass(bool (*Transform)(VPlan &, ArgsTy...), VPlan &Plan,
+ typename std::remove_reference<ArgsTy>::type &...Args) {
+ bool Res = Transform(Plan, Args...);
+ if (VerifyEachVPlan)
+ verifyVPlanIsValid(Plan);
+ return Res;
+ }
+ /// Helper to run a VPlan transform \p Transform on \p VPlan, forwarding extra
+ /// arguments to the transform.
+ template <typename... ArgsTy>
+ static void runPass(void (*Fn)(VPlan &, ArgsTy...), VPlan &Plan,
+ typename std::remove_reference<ArgsTy>::type &...Args) {
+ Fn(Plan, Args...);
+ if (VerifyEachVPlan)
+ verifyVPlanIsValid(Plan);
+ }
+
/// Replaces the VPInstructions in \p Plan with corresponding
/// widen recipes.
static void
@@ -100,7 +124,8 @@ struct VPlanTransforms {
/// TODO: Replace BlockNeedsPredication callback with retrieving info from
/// VPlan directly.
static void dropPoisonGeneratingRecipes(
- VPlan &Plan, function_ref<bool(BasicBlock *)> BlockNeedsPredication);
+ VPlan &Plan,
+ const std::function<bool(BasicBlock *)> &BlockNeedsPredication);
/// Add a VPEVLBasedIVPHIRecipe and related recipes to \p Plan and
/// replaces all uses except the canonical IV increment of
@@ -119,7 +144,7 @@ struct VPlanTransforms {
VPlan &Plan,
const SmallPtrSetImpl<const InterleaveGroup<Instruction> *>
&InterleaveGroups,
- VPRecipeBuilder &RecipeBuilder, bool ScalarEpilogueAllowed);
+ VPRecipeBuilder &RecipeBuilder, const bool &ScalarEpilogueAllowed);
/// Remove dead recipes from \p Plan.
static void removeDeadRecipes(VPlan &Plan);
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Add new runPass helpers to run a VPlan transformation. This makes it easier to add additional checks/functionality for each transform run. In this patch, an option is added to run the verifier after each VPlan transform. Follow-ups will use the same helper to also support printing VPlans after each transform.
✅ With the latest revision this PR passed the C/C++ code formatter. |
…NFC). (#123640) Add new runPass helpers to run a VPlan transformation. This makes it easier to add additional checks/functionality for each transform run. In this patch, an option is added to run the verifier after each VPlan transform. Follow-ups will use the same helper to also support printing VPlans after each transform. Note that the verifier at the moment requires there to be a canonical IV and vector loop region, so the final lowering transforms aren't run via runPass yet. PR: llvm/llvm-project#123640
Add new runPass helpers to run a VPlan transformation. This makes it easier to add additional checks/functionality for each transform run. In this patch, an option is added to run the verifier after each VPlan transform.
Follow-ups will use the same helper to also support printing VPlans after each transform.
Note that the verifier at the moment requires there to be a canonical IV and vector loop region, so the final lowering transforms aren't run via runPass yet.