[llvm] [VPlan] Fold VPDef into VPRecipeBase (NFC). (PR #174282)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 11 08:58:45 PST 2026


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/174282

>From 4065d582bcbab37c6ac09e8747e16faf12734a60 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 2 Jan 2026 20:18:02 +0000
Subject: [PATCH 1/3] [VPlan] Merge VPDef into VPRecipeBase (NFC).

A separate VDef is not needed any longer, fold i into VPRecipeBase to
simplify code and class hierarchy.

Depends on https://github.com/llvm/llvm-project/pull/172758.
---
 llvm/docs/VectorizationPlan.rst               |   8 +-
 .../Transforms/Vectorize/LoopVectorize.cpp    |  66 +--
 llvm/lib/Transforms/Vectorize/VPlan.cpp       |  12 +-
 llvm/lib/Transforms/Vectorize/VPlan.h         | 433 +++++++++++-------
 .../lib/Transforms/Vectorize/VPlanRecipes.cpp |  14 +-
 .../Transforms/Vectorize/VPlanTransforms.cpp  |   8 +-
 llvm/lib/Transforms/Vectorize/VPlanValue.h    | 161 +------
 .../Transforms/Vectorize/VPlanTest.cpp        |  59 +--
 8 files changed, 342 insertions(+), 419 deletions(-)

diff --git a/llvm/docs/VectorizationPlan.rst b/llvm/docs/VectorizationPlan.rst
index 73e9e6098175a..b8db8cab843cf 100644
--- a/llvm/docs/VectorizationPlan.rst
+++ b/llvm/docs/VectorizationPlan.rst
@@ -186,7 +186,8 @@ The low-level design of VPlan comprises of the following classes.
   input IR instructions are referred to as "Ingredients" of the Recipe. A Recipe
   may specify how its ingredients are to be transformed to produce the output IR
   instructions; e.g., cloned once, replicated multiple times or widened
-  according to selected VF.
+  according to selected VF. VPRecipeBase also defines zero, one or multiple
+  VPValues, modeling the fact that recipes can produce multiple results.
 
 :VPValue:
   The base of VPlan's def-use relations class hierarchy. When instantiated, it
@@ -197,11 +198,6 @@ The low-level design of VPlan comprises of the following classes.
   A VPUser represents an entity that uses a number of VPValues as operands.
   VPUser is similar in some aspects to LLVM's User class.
 
-:VPDef:
-  A VPDef represents an entity that defines zero, one or multiple VPValues.
-  It is used to model the fact that recipes in VPlan can define multiple
-  VPValues.
-
 :VPInstruction:
   A VPInstruction is a recipe characterized by a single opcode and optional
   flags, free of ingredients or other meta-data. VPInstructions also extend
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index b61890aaa3ded..92447c737e9c7 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -4111,40 +4111,40 @@ static bool willGenerateVectors(VPlan &Plan, ElementCount VF,
       // result. Note that this includes VPInstruction where some opcodes may
       // produce a vector, to preserve existing behavior as VPInstructions model
       // aspects not directly mapped to existing IR instructions.
-      switch (R.getVPDefID()) {
-      case VPDef::VPDerivedIVSC:
-      case VPDef::VPScalarIVStepsSC:
-      case VPDef::VPReplicateSC:
-      case VPDef::VPInstructionSC:
-      case VPDef::VPCanonicalIVPHISC:
-      case VPDef::VPVectorPointerSC:
-      case VPDef::VPVectorEndPointerSC:
-      case VPDef::VPExpandSCEVSC:
-      case VPDef::VPEVLBasedIVPHISC:
-      case VPDef::VPPredInstPHISC:
-      case VPDef::VPBranchOnMaskSC:
+      switch (R.getVPRecipeID()) {
+      case VPRecipeBase::VPDerivedIVSC:
+      case VPRecipeBase::VPScalarIVStepsSC:
+      case VPRecipeBase::VPReplicateSC:
+      case VPRecipeBase::VPInstructionSC:
+      case VPRecipeBase::VPCanonicalIVPHISC:
+      case VPRecipeBase::VPVectorPointerSC:
+      case VPRecipeBase::VPVectorEndPointerSC:
+      case VPRecipeBase::VPExpandSCEVSC:
+      case VPRecipeBase::VPEVLBasedIVPHISC:
+      case VPRecipeBase::VPPredInstPHISC:
+      case VPRecipeBase::VPBranchOnMaskSC:
         continue;
-      case VPDef::VPReductionSC:
-      case VPDef::VPActiveLaneMaskPHISC:
-      case VPDef::VPWidenCallSC:
-      case VPDef::VPWidenCanonicalIVSC:
-      case VPDef::VPWidenCastSC:
-      case VPDef::VPWidenGEPSC:
-      case VPDef::VPWidenIntrinsicSC:
-      case VPDef::VPWidenSC:
-      case VPDef::VPBlendSC:
-      case VPDef::VPFirstOrderRecurrencePHISC:
-      case VPDef::VPHistogramSC:
-      case VPDef::VPWidenPHISC:
-      case VPDef::VPWidenIntOrFpInductionSC:
-      case VPDef::VPWidenPointerInductionSC:
-      case VPDef::VPReductionPHISC:
-      case VPDef::VPInterleaveEVLSC:
-      case VPDef::VPInterleaveSC:
-      case VPDef::VPWidenLoadEVLSC:
-      case VPDef::VPWidenLoadSC:
-      case VPDef::VPWidenStoreEVLSC:
-      case VPDef::VPWidenStoreSC:
+      case VPRecipeBase::VPReductionSC:
+      case VPRecipeBase::VPActiveLaneMaskPHISC:
+      case VPRecipeBase::VPWidenCallSC:
+      case VPRecipeBase::VPWidenCanonicalIVSC:
+      case VPRecipeBase::VPWidenCastSC:
+      case VPRecipeBase::VPWidenGEPSC:
+      case VPRecipeBase::VPWidenIntrinsicSC:
+      case VPRecipeBase::VPWidenSC:
+      case VPRecipeBase::VPBlendSC:
+      case VPRecipeBase::VPFirstOrderRecurrencePHISC:
+      case VPRecipeBase::VPHistogramSC:
+      case VPRecipeBase::VPWidenPHISC:
+      case VPRecipeBase::VPWidenIntOrFpInductionSC:
+      case VPRecipeBase::VPWidenPointerInductionSC:
+      case VPRecipeBase::VPReductionPHISC:
+      case VPRecipeBase::VPInterleaveEVLSC:
+      case VPRecipeBase::VPInterleaveSC:
+      case VPRecipeBase::VPWidenLoadEVLSC:
+      case VPRecipeBase::VPWidenLoadSC:
+      case VPRecipeBase::VPWidenStoreEVLSC:
+      case VPRecipeBase::VPWidenStoreSC:
         break;
       default:
         llvm_unreachable("unhandled recipe");
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index a6a46e36b397d..5f050627a1fbc 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -107,10 +107,8 @@ void VPValue::dump() const {
   dbgs() << "\n";
 }
 
-void VPDef::dump() const {
-  const VPRecipeBase *Instr = dyn_cast_or_null<VPRecipeBase>(this);
-  VPSlotTracker SlotTracker(
-      (Instr && Instr->getParent()) ? Instr->getParent()->getPlan() : nullptr);
+void VPRecipeBase::dump() const {
+  VPSlotTracker SlotTracker(getParent() ? getParent()->getPlan() : nullptr);
   print(dbgs(), "", SlotTracker);
   dbgs() << "\n";
 }
@@ -120,14 +118,14 @@ VPRecipeBase *VPValue::getDefiningRecipe() {
   auto *DefValue = dyn_cast<VPRecipeValue>(this);
   if (!DefValue)
     return nullptr;
-  return cast<VPRecipeBase>(DefValue->Def);
+  return DefValue->Def;
 }
 
 const VPRecipeBase *VPValue::getDefiningRecipe() const {
   auto *DefValue = dyn_cast<VPRecipeValue>(this);
   if (!DefValue)
     return nullptr;
-  return cast<VPRecipeBase>(DefValue->Def);
+  return DefValue->Def;
 }
 
 Value *VPValue::getLiveInIRValue() const {
@@ -136,7 +134,7 @@ Value *VPValue::getLiveInIRValue() const {
 
 Type *VPIRValue::getType() const { return getUnderlyingValue()->getType(); }
 
-VPRecipeValue::VPRecipeValue(VPDef *Def, Value *UV)
+VPRecipeValue::VPRecipeValue(VPRecipeBase *Def, Value *UV)
     : VPValue(VPVRecipeValueSC, UV), Def(Def) {
   assert(Def && "VPRecipeValue requires a defining recipe");
   Def->addDefinedValue(this);
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 0fa5180f690ab..c054be345d008 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -377,16 +377,16 @@ class LLVM_ABI_FOR_TEST VPBlockBase {
 };
 
 /// VPRecipeBase is a base class modeling a sequence of one or more output IR
-/// instructions. VPRecipeBase owns the VPValues it defines through VPDef
-/// and is responsible for deleting its defined values. Single-value
-/// recipes must inherit from VPSingleDef instead of inheriting from both
-/// VPRecipeBase and VPValue separately.
+/// instructions. VPRecipeBase owns the VPValues it defines and is responsible
+/// for deleting its defined values. Single-value recipes must inherit from
+/// VPSingleDefRecipe instead of inheriting from both VPRecipeBase and VPValue
+/// separately.
 class LLVM_ABI_FOR_TEST VPRecipeBase
     : public ilist_node_with_parent<VPRecipeBase, VPBasicBlock>,
-      public VPDef,
       public VPUser {
   friend VPBasicBlock;
   friend class VPBlockUtils;
+  friend class VPRecipeValue;
 
   /// Each VPRecipe belongs to a single VPBasicBlock.
   VPBasicBlock *Parent = nullptr;
@@ -394,12 +394,133 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
   /// The debug location for the recipe.
   DebugLoc DL;
 
+  /// Subclass identifier (for isa/dyn_cast).
+  const unsigned char SubclassID;
+
+  /// The VPValues defined by this VPRecipeBase.
+  TinyPtrVector<VPRecipeValue *> DefinedValues;
+
+  /// Add \p V as a defined value by this VPRecipeBase.
+  void addDefinedValue(VPRecipeValue *V) {
+    assert(V->Def == this &&
+           "can only add VPValue already linked with this VPRecipeBase");
+    DefinedValues.push_back(V);
+  }
+
+  /// Remove \p V from the values defined by this VPRecipeBase. \p V must be a
+  /// defined value of this VPRecipeBase.
+  void removeDefinedValue(VPRecipeValue *V) {
+    assert(V->Def == this &&
+           "can only remove VPValue linked with this VPRecipeBase");
+    assert(is_contained(DefinedValues, V) &&
+           "VPValue to remove must be in DefinedValues");
+    llvm::erase(DefinedValues, V);
+    V->Def = nullptr;
+  }
+
 public:
+  /// An enumeration for keeping track of the concrete subclass of VPRecipeBase
+  /// that is actually instantiated. Values of this enumeration are kept in the
+  /// SubclassID field of the VPRecipeBase objects. They are used for concrete
+  /// type identification.
+  using VPRecipeTy = enum {
+    VPBranchOnMaskSC,
+    VPDerivedIVSC,
+    VPExpandSCEVSC,
+    VPExpressionSC,
+    VPIRInstructionSC,
+    VPInstructionSC,
+    VPInterleaveEVLSC,
+    VPInterleaveSC,
+    VPReductionEVLSC,
+    VPReductionSC,
+    VPReplicateSC,
+    VPScalarIVStepsSC,
+    VPVectorPointerSC,
+    VPVectorEndPointerSC,
+    VPWidenCallSC,
+    VPWidenCanonicalIVSC,
+    VPWidenCastSC,
+    VPWidenGEPSC,
+    VPWidenIntrinsicSC,
+    VPWidenLoadEVLSC,
+    VPWidenLoadSC,
+    VPWidenStoreEVLSC,
+    VPWidenStoreSC,
+    VPWidenSC,
+    VPWidenSelectSC,
+    VPBlendSC,
+    VPHistogramSC,
+    // START: Phi-like recipes. Need to be kept together.
+    VPWidenPHISC,
+    VPPredInstPHISC,
+    // START: SubclassID for recipes that inherit VPHeaderPHIRecipe.
+    // VPHeaderPHIRecipe need to be kept together.
+    VPCanonicalIVPHISC,
+    VPActiveLaneMaskPHISC,
+    VPEVLBasedIVPHISC,
+    VPFirstOrderRecurrencePHISC,
+    VPWidenIntOrFpInductionSC,
+    VPWidenPointerInductionSC,
+    VPReductionPHISC,
+    // END: SubclassID for recipes that inherit VPHeaderPHIRecipe
+    // END: Phi-like recipes
+    VPFirstPHISC = VPWidenPHISC,
+    VPFirstHeaderPHISC = VPCanonicalIVPHISC,
+    VPLastHeaderPHISC = VPReductionPHISC,
+    VPLastPHISC = VPReductionPHISC,
+  };
+
   VPRecipeBase(const unsigned char SC, ArrayRef<VPValue *> Operands,
                DebugLoc DL = DebugLoc::getUnknown())
-      : VPDef(SC), VPUser(Operands), DL(DL) {}
+      : VPUser(Operands), DL(DL), SubclassID(SC) {}
+
+  virtual ~VPRecipeBase() {
+    for (VPRecipeValue *D : to_vector(DefinedValues)) {
+      assert(
+          D->Def == this &&
+          "all defined VPValues should point to the containing VPRecipeBase");
+      assert(D->getNumUsers() == 0 &&
+             "all defined VPValues should have no more users");
+      delete D;
+    }
+  }
+
+  /// Returns the only VPValue defined by the VPRecipeBase. Can only be called
+  /// for VPRecipeBases with a single defined value.
+  VPValue *getVPSingleValue() {
+    assert(DefinedValues.size() == 1 && "must have exactly one defined value");
+    assert(DefinedValues[0] && "defined value must be non-null");
+    return DefinedValues[0];
+  }
+  const VPValue *getVPSingleValue() const {
+    assert(DefinedValues.size() == 1 && "must have exactly one defined value");
+    assert(DefinedValues[0] && "defined value must be non-null");
+    return DefinedValues[0];
+  }
+
+  /// Returns the VPValue with index \p I defined by the VPRecipeBase.
+  VPValue *getVPValue(unsigned I) {
+    assert(DefinedValues[I] && "defined value must be non-null");
+    return DefinedValues[I];
+  }
+  const VPValue *getVPValue(unsigned I) const {
+    assert(DefinedValues[I] && "defined value must be non-null");
+    return DefinedValues[I];
+  }
+
+  /// Returns an ArrayRef of the values defined by the VPRecipeBase.
+  ArrayRef<VPRecipeValue *> definedValues() { return DefinedValues; }
+  /// Returns an ArrayRef of the values defined by the VPRecipeBase.
+  ArrayRef<VPRecipeValue *> definedValues() const { return DefinedValues; }
 
-  ~VPRecipeBase() override = default;
+  /// Returns the number of values defined by the VPRecipeBase.
+  unsigned getNumDefinedValues() const { return DefinedValues.size(); }
+
+  /// \return an ID for the concrete type of this object.
+  /// This is used to implement the classof checks. This should not be used
+  /// for any other purpose, as the values may change as LLVM evolves.
+  unsigned getVPRecipeID() const { return SubclassID; }
 
   /// Clone the current recipe.
   virtual VPRecipeBase *clone() = 0;
@@ -451,11 +572,6 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
   iplist<VPRecipeBase>::iterator eraseFromParent();
 
   /// Method to support type inquiry through isa, cast, and dyn_cast.
-  static inline bool classof(const VPDef *D) {
-    // All VPDefs are also VPRecipeBases.
-    return true;
-  }
-
   static inline bool classof(const VPUser *U) { return true; }
 
   /// Returns true if the recipe may have side-effects.
@@ -485,9 +601,12 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
   void setDebugLoc(DebugLoc NewDL) { DL = NewDL; }
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  /// Dump the recipe to stderr (for debugging).
+  LLVM_ABI_FOR_TEST void dump() const;
+
   /// Print the recipe, delegating to printRecipe().
   void print(raw_ostream &O, const Twine &Indent,
-             VPSlotTracker &SlotTracker) const override final;
+             VPSlotTracker &SlotTracker) const;
 #endif
 
 protected:
@@ -506,23 +625,20 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
 };
 
 // Helper macro to define common classof implementations for recipes.
-#define VP_CLASSOF_IMPL(VPDefID)                                               \
-  static inline bool classof(const VPDef *D) {                                 \
-    return D->getVPDefID() == VPDefID;                                         \
+#define VP_CLASSOF_IMPL(VPRecipeID)                                            \
+  static inline bool classof(const VPRecipeBase *R) {                          \
+    return R->getVPRecipeID() == VPRecipeID;                                   \
   }                                                                            \
   static inline bool classof(const VPValue *V) {                               \
     auto *R = V->getDefiningRecipe();                                          \
-    return R && R->getVPDefID() == VPDefID;                                    \
+    return R && R->getVPRecipeID() == VPRecipeID;                              \
   }                                                                            \
   static inline bool classof(const VPUser *U) {                                \
     auto *R = dyn_cast<VPRecipeBase>(U);                                       \
-    return R && R->getVPDefID() == VPDefID;                                    \
-  }                                                                            \
-  static inline bool classof(const VPRecipeBase *R) {                          \
-    return R->getVPDefID() == VPDefID;                                         \
+    return R && R->getVPRecipeID() == VPRecipeID;                              \
   }                                                                            \
   static inline bool classof(const VPSingleDefRecipe *R) {                     \
-    return R->getVPDefID() == VPDefID;                                         \
+    return R->getVPRecipeID() == VPRecipeID;                                   \
   }
 
 /// VPSingleDef is a base class for recipes for modeling a sequence of one or
@@ -539,7 +655,7 @@ class VPSingleDefRecipe : public VPRecipeBase, public VPRecipeValue {
       : VPRecipeBase(SC, Operands, DL), VPRecipeValue(this, UV) {}
 
   static inline bool classof(const VPRecipeBase *R) {
-    switch (R->getVPDefID()) {
+    switch (R->getVPRecipeID()) {
     case VPRecipeBase::VPDerivedIVSC:
     case VPRecipeBase::VPEVLBasedIVPHISC:
     case VPRecipeBase::VPExpandSCEVSC:
@@ -580,7 +696,7 @@ class VPSingleDefRecipe : public VPRecipeBase, public VPRecipeValue {
       // the recipes to be able to make widened loads VPSingleDefRecipes.
       return false;
     }
-    llvm_unreachable("Unhandled VPDefID");
+    llvm_unreachable("Unhandled VPRecipeID");
   }
 
   static inline bool classof(const VPUser *U) {
@@ -926,17 +1042,17 @@ struct VPRecipeWithIRFlags : public VPSingleDefRecipe, public VPIRFlags {
       : VPSingleDefRecipe(SC, Operands, DL), VPIRFlags(Flags) {}
 
   static inline bool classof(const VPRecipeBase *R) {
-    return R->getVPDefID() == VPRecipeBase::VPInstructionSC ||
-           R->getVPDefID() == VPRecipeBase::VPWidenSC ||
-           R->getVPDefID() == VPRecipeBase::VPWidenGEPSC ||
-           R->getVPDefID() == VPRecipeBase::VPWidenCallSC ||
-           R->getVPDefID() == VPRecipeBase::VPWidenCastSC ||
-           R->getVPDefID() == VPRecipeBase::VPWidenIntrinsicSC ||
-           R->getVPDefID() == VPRecipeBase::VPReductionSC ||
-           R->getVPDefID() == VPRecipeBase::VPReductionEVLSC ||
-           R->getVPDefID() == VPRecipeBase::VPReplicateSC ||
-           R->getVPDefID() == VPRecipeBase::VPVectorEndPointerSC ||
-           R->getVPDefID() == VPRecipeBase::VPVectorPointerSC;
+    return R->getVPRecipeID() == VPRecipeBase::VPInstructionSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPWidenSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPWidenGEPSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPWidenCallSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPWidenCastSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPWidenIntrinsicSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPReductionSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPReductionEVLSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPReplicateSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPVectorEndPointerSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPVectorPointerSC;
   }
 
   static inline bool classof(const VPUser *U) {
@@ -945,15 +1061,14 @@ struct VPRecipeWithIRFlags : public VPSingleDefRecipe, public VPIRFlags {
   }
 
   static inline bool classof(const VPValue *V) {
-    auto *R = dyn_cast_or_null<VPRecipeBase>(V->getDefiningRecipe());
+    auto *R = V->getDefiningRecipe();
     return R && classof(R);
   }
 
   VPRecipeWithIRFlags *clone() override = 0;
 
-  static inline bool classof(const VPSingleDefRecipe *U) {
-    auto *R = dyn_cast<VPRecipeBase>(U);
-    return R && classof(R);
+  static inline bool classof(const VPSingleDefRecipe *R) {
+    return classof(static_cast<const VPRecipeBase *>(R));
   }
 
   void execute(VPTransformState &State) override = 0;
@@ -1178,7 +1293,7 @@ class LLVM_ABI_FOR_TEST VPInstruction : public VPRecipeWithIRFlags,
                 const VPIRFlags &Flags = {}, const VPIRMetadata &MD = {},
                 DebugLoc DL = DebugLoc::getUnknown(), const Twine &Name = "");
 
-  VP_CLASSOF_IMPL(VPDef::VPInstructionSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPInstructionSC)
 
   VPInstruction *clone() override {
     auto *New = new VPInstruction(Opcode, operands(), *this, *this,
@@ -1260,7 +1375,7 @@ class LLVM_ABI_FOR_TEST VPInstruction : public VPRecipeWithIRFlags,
 
 /// A specialization of VPInstruction augmenting it with a dedicated result
 /// type, to be used when the opcode and operands of the VPInstruction don't
-/// directly determine the result type. Note that there is no separate VPDef ID
+/// directly determine the result type. Note that there is no separate recipe ID
 /// for VPInstructionWithType; it shares the same ID as VPInstruction and is
 /// distinguished purely by the opcode.
 class VPInstructionWithType : public VPInstruction {
@@ -1430,7 +1545,8 @@ class VPIRInstruction : public VPRecipeBase {
   /// VPIRInstruction::create() should be used to create VPIRInstructions, as
   /// subclasses may need to be created, e.g. VPIRPhi.
   VPIRInstruction(Instruction &I)
-      : VPRecipeBase(VPDef::VPIRInstructionSC, ArrayRef<VPValue *>()), I(I) {}
+      : VPRecipeBase(VPRecipeBase::VPIRInstructionSC, ArrayRef<VPValue *>()),
+        I(I) {}
 
 public:
   ~VPIRInstruction() override = default;
@@ -1439,7 +1555,7 @@ class VPIRInstruction : public VPRecipeBase {
   /// VPIRInstruction.
   LLVM_ABI_FOR_TEST static VPIRInstruction *create(Instruction &I);
 
-  VP_CLASSOF_IMPL(VPDef::VPIRInstructionSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPIRInstructionSC)
 
   VPIRInstruction *clone() override {
     auto *R = create(I);
@@ -1526,7 +1642,7 @@ class LLVM_ABI_FOR_TEST VPWidenRecipe : public VPRecipeWithIRFlags,
   VPWidenRecipe(Instruction &I, ArrayRef<VPValue *> Operands,
                 const VPIRFlags &Flags = {}, const VPIRMetadata &Metadata = {},
                 DebugLoc DL = {})
-      : VPRecipeWithIRFlags(VPDef::VPWidenSC, Operands, Flags, DL),
+      : VPRecipeWithIRFlags(VPRecipeBase::VPWidenSC, Operands, Flags, DL),
         VPIRMetadata(Metadata), Opcode(I.getOpcode()) {
     setUnderlyingValue(&I);
   }
@@ -1538,7 +1654,7 @@ class LLVM_ABI_FOR_TEST VPWidenRecipe : public VPRecipeWithIRFlags,
                              getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenSC)
 
   /// Produce a widened instruction using the opcode and operands of the recipe,
   /// processing State.VF elements.
@@ -1579,7 +1695,7 @@ class VPWidenCastRecipe : public VPRecipeWithIRFlags, public VPIRMetadata {
                     CastInst *CI = nullptr, const VPIRFlags &Flags = {},
                     const VPIRMetadata &Metadata = {},
                     DebugLoc DL = DebugLoc::getUnknown())
-      : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op, Flags, DL),
+      : VPRecipeWithIRFlags(VPRecipeBase::VPWidenCastSC, Op, Flags, DL),
         VPIRMetadata(Metadata), Opcode(Opcode), ResultTy(ResultTy) {
     assert(flagsValidForOpcode(Opcode) &&
            "Set flags not supported for the provided opcode");
@@ -1594,7 +1710,7 @@ class VPWidenCastRecipe : public VPRecipeWithIRFlags, public VPIRMetadata {
                                  *this, *this, getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenCastSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenCastSC)
 
   /// Produce widened copies of the cast.
   LLVM_ABI_FOR_TEST void execute(VPTransformState &State) override;
@@ -1639,8 +1755,8 @@ class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags, public VPIRMetadata {
                          const VPIRFlags &Flags = {},
                          const VPIRMetadata &MD = {},
                          DebugLoc DL = DebugLoc::getUnknown())
-      : VPRecipeWithIRFlags(VPDef::VPWidenIntrinsicSC, CallArguments, Flags,
-                            DL),
+      : VPRecipeWithIRFlags(VPRecipeBase::VPWidenIntrinsicSC, CallArguments,
+                            Flags, DL),
         VPIRMetadata(MD), VectorIntrinsicID(VectorIntrinsicID), ResultTy(Ty),
         MayReadFromMemory(CI.mayReadFromMemory()),
         MayWriteToMemory(CI.mayWriteToMemory()),
@@ -1653,8 +1769,8 @@ class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags, public VPIRMetadata {
                          const VPIRFlags &Flags = {},
                          const VPIRMetadata &Metadata = {},
                          DebugLoc DL = DebugLoc::getUnknown())
-      : VPRecipeWithIRFlags(VPDef::VPWidenIntrinsicSC, CallArguments, Flags,
-                            DL),
+      : VPRecipeWithIRFlags(VPRecipeBase::VPWidenIntrinsicSC, CallArguments,
+                            Flags, DL),
         VPIRMetadata(Metadata), VectorIntrinsicID(VectorIntrinsicID),
         ResultTy(Ty) {
     LLVMContext &Ctx = Ty->getContext();
@@ -1678,7 +1794,7 @@ class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags, public VPIRMetadata {
                                       *this, *this, getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenIntrinsicSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenIntrinsicSC)
 
   /// Produce a widened version of the vector intrinsic.
   LLVM_ABI_FOR_TEST void execute(VPTransformState &State) override;
@@ -1728,7 +1844,8 @@ class LLVM_ABI_FOR_TEST VPWidenCallRecipe : public VPRecipeWithIRFlags,
                     ArrayRef<VPValue *> CallArguments,
                     const VPIRFlags &Flags = {},
                     const VPIRMetadata &Metadata = {}, DebugLoc DL = {})
-      : VPRecipeWithIRFlags(VPDef::VPWidenCallSC, CallArguments, Flags, DL),
+      : VPRecipeWithIRFlags(VPRecipeBase::VPWidenCallSC, CallArguments, Flags,
+                            DL),
         VPIRMetadata(Metadata), Variant(Variant) {
     setUnderlyingValue(UV);
     assert(
@@ -1743,7 +1860,7 @@ class LLVM_ABI_FOR_TEST VPWidenCallRecipe : public VPRecipeWithIRFlags,
                                  *this, *this, getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenCallSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenCallSC)
 
   /// Produce a widened version of the call instruction.
   void execute(VPTransformState &State) override;
@@ -1779,7 +1896,8 @@ class VPHistogramRecipe : public VPRecipeBase {
 public:
   VPHistogramRecipe(unsigned Opcode, ArrayRef<VPValue *> Operands,
                     DebugLoc DL = DebugLoc::getUnknown())
-      : VPRecipeBase(VPDef::VPHistogramSC, Operands, DL), Opcode(Opcode) {}
+      : VPRecipeBase(VPRecipeBase::VPHistogramSC, Operands, DL),
+        Opcode(Opcode) {}
 
   ~VPHistogramRecipe() override = default;
 
@@ -1787,7 +1905,7 @@ class VPHistogramRecipe : public VPRecipeBase {
     return new VPHistogramRecipe(Opcode, operands(), getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPHistogramSC);
+  VP_CLASSOF_IMPL(VPRecipeBase::VPHistogramSC);
 
   /// Produce a vectorized histogram operation.
   void execute(VPTransformState &State) override;
@@ -1828,7 +1946,7 @@ class LLVM_ABI_FOR_TEST VPWidenGEPRecipe : public VPRecipeWithIRFlags {
   VPWidenGEPRecipe(GetElementPtrInst *GEP, ArrayRef<VPValue *> Operands,
                    const VPIRFlags &Flags = {},
                    DebugLoc DL = DebugLoc::getUnknown())
-      : VPRecipeWithIRFlags(VPDef::VPWidenGEPSC, Operands, Flags, DL),
+      : VPRecipeWithIRFlags(VPRecipeBase::VPWidenGEPSC, Operands, Flags, DL),
         SourceElementTy(GEP->getSourceElementType()) {
     setUnderlyingValue(GEP);
     SmallVector<std::pair<unsigned, MDNode *>> Metadata;
@@ -1844,7 +1962,7 @@ class LLVM_ABI_FOR_TEST VPWidenGEPRecipe : public VPRecipeWithIRFlags {
                                 operands(), *this, getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenGEPSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenGEPSC)
 
   /// This recipe generates a GEP instruction.
   unsigned getOpcode() const { return Instruction::GetElementPtr; }
@@ -1886,13 +2004,13 @@ class VPVectorEndPointerRecipe : public VPRecipeWithIRFlags,
 public:
   VPVectorEndPointerRecipe(VPValue *Ptr, VPValue *VF, Type *IndexedTy,
                            int64_t Stride, GEPNoWrapFlags GEPFlags, DebugLoc DL)
-      : VPRecipeWithIRFlags(VPDef::VPVectorEndPointerSC,
+      : VPRecipeWithIRFlags(VPRecipeBase::VPVectorEndPointerSC,
                             ArrayRef<VPValue *>({Ptr, VF}), GEPFlags, DL),
         IndexedTy(IndexedTy), Stride(Stride) {
     assert(Stride < 0 && "Stride must be negative");
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPVectorEndPointerSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPVectorEndPointerSC)
 
   VPValue *getVFValue() { return getOperand(1); }
   const VPValue *getVFValue() const { return getOperand(1); }
@@ -1943,10 +2061,10 @@ class VPVectorPointerRecipe : public VPRecipeWithIRFlags {
 public:
   VPVectorPointerRecipe(VPValue *Ptr, Type *SourceElementTy,
                         GEPNoWrapFlags GEPFlags, DebugLoc DL)
-      : VPRecipeWithIRFlags(VPDef::VPVectorPointerSC, Ptr, GEPFlags, DL),
+      : VPRecipeWithIRFlags(VPRecipeBase::VPVectorPointerSC, Ptr, GEPFlags, DL),
         SourceElementTy(SourceElementTy) {}
 
-  VP_CLASSOF_IMPL(VPDef::VPVectorPointerSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPVectorPointerSC)
 
   VPValue *getOffset() {
     return getNumOperands() == 2 ? getOperand(1) : nullptr;
@@ -2019,9 +2137,9 @@ class VPVectorPointerRecipe : public VPRecipeWithIRFlags {
 class LLVM_ABI_FOR_TEST VPHeaderPHIRecipe : public VPSingleDefRecipe,
                                             public VPPhiAccessors {
 protected:
-  VPHeaderPHIRecipe(unsigned char VPDefID, Instruction *UnderlyingInstr,
+  VPHeaderPHIRecipe(unsigned char VPRecipeID, Instruction *UnderlyingInstr,
                     VPValue *Start, DebugLoc DL = DebugLoc::getUnknown())
-      : VPSingleDefRecipe(VPDefID, ArrayRef<VPValue *>({Start}),
+      : VPSingleDefRecipe(VPRecipeID, ArrayRef<VPValue *>({Start}),
                           UnderlyingInstr, DL) {}
 
   const VPRecipeBase *getAsRecipe() const override { return this; }
@@ -2031,8 +2149,8 @@ class LLVM_ABI_FOR_TEST VPHeaderPHIRecipe : public VPSingleDefRecipe,
 
   /// Method to support type inquiry through isa, cast, and dyn_cast.
   static inline bool classof(const VPRecipeBase *R) {
-    return R->getVPDefID() >= VPDef::VPFirstHeaderPHISC &&
-           R->getVPDefID() <= VPDef::VPLastHeaderPHISC;
+    return R->getVPRecipeID() >= VPRecipeBase::VPFirstHeaderPHISC &&
+           R->getVPRecipeID() <= VPRecipeBase::VPLastHeaderPHISC;
   }
   static inline bool classof(const VPValue *V) {
     return isa<VPHeaderPHIRecipe>(V->getDefiningRecipe());
@@ -2096,8 +2214,8 @@ class VPWidenInductionRecipe : public VPHeaderPHIRecipe {
   }
 
   static inline bool classof(const VPRecipeBase *R) {
-    return R->getVPDefID() == VPDef::VPWidenIntOrFpInductionSC ||
-           R->getVPDefID() == VPDef::VPWidenPointerInductionSC;
+    return R->getVPRecipeID() == VPRecipeBase::VPWidenIntOrFpInductionSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPWidenPointerInductionSC;
   }
 
   static inline bool classof(const VPValue *V) {
@@ -2173,8 +2291,8 @@ class VPWidenIntOrFpInductionRecipe : public VPWidenInductionRecipe,
   VPWidenIntOrFpInductionRecipe(PHINode *IV, VPIRValue *Start, VPValue *Step,
                                 VPValue *VF, const InductionDescriptor &IndDesc,
                                 const VPIRFlags &Flags, DebugLoc DL)
-      : VPWidenInductionRecipe(VPDef::VPWidenIntOrFpInductionSC, IV, Start,
-                               Step, IndDesc, DL),
+      : VPWidenInductionRecipe(VPRecipeBase::VPWidenIntOrFpInductionSC, IV,
+                               Start, Step, IndDesc, DL),
         VPIRFlags(Flags), Trunc(nullptr) {
     addOperand(VF);
   }
@@ -2183,8 +2301,8 @@ class VPWidenIntOrFpInductionRecipe : public VPWidenInductionRecipe,
                                 VPValue *VF, const InductionDescriptor &IndDesc,
                                 TruncInst *Trunc, const VPIRFlags &Flags,
                                 DebugLoc DL)
-      : VPWidenInductionRecipe(VPDef::VPWidenIntOrFpInductionSC, IV, Start,
-                               Step, IndDesc, DL),
+      : VPWidenInductionRecipe(VPRecipeBase::VPWidenIntOrFpInductionSC, IV,
+                               Start, Step, IndDesc, DL),
         VPIRFlags(Flags), Trunc(Trunc) {
     addOperand(VF);
     SmallVector<std::pair<unsigned, MDNode *>> Metadata;
@@ -2202,7 +2320,7 @@ class VPWidenIntOrFpInductionRecipe : public VPWidenInductionRecipe,
         getInductionDescriptor(), Trunc, *this, getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenIntOrFpInductionSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenIntOrFpInductionSC)
 
   void execute(VPTransformState &State) override {
     llvm_unreachable("cannot execute this recipe, should be expanded via "
@@ -2261,8 +2379,8 @@ class VPWidenPointerInductionRecipe : public VPWidenInductionRecipe {
   VPWidenPointerInductionRecipe(PHINode *Phi, VPValue *Start, VPValue *Step,
                                 VPValue *NumUnrolledElems,
                                 const InductionDescriptor &IndDesc, DebugLoc DL)
-      : VPWidenInductionRecipe(VPDef::VPWidenPointerInductionSC, Phi, Start,
-                               Step, IndDesc, DL) {
+      : VPWidenInductionRecipe(VPRecipeBase::VPWidenPointerInductionSC, Phi,
+                               Start, Step, IndDesc, DL) {
     addOperand(NumUnrolledElems);
   }
 
@@ -2274,7 +2392,7 @@ class VPWidenPointerInductionRecipe : public VPWidenInductionRecipe {
         getOperand(2), getInductionDescriptor(), getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenPointerInductionSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenPointerInductionSC)
 
   /// Generate vector values for the pointer induction.
   void execute(VPTransformState &State) override {
@@ -2308,7 +2426,8 @@ class LLVM_ABI_FOR_TEST VPWidenPHIRecipe : public VPSingleDefRecipe,
   /// debug location \p DL.
   VPWidenPHIRecipe(PHINode *Phi, VPValue *Start = nullptr,
                    DebugLoc DL = DebugLoc::getUnknown(), const Twine &Name = "")
-      : VPSingleDefRecipe(VPDef::VPWidenPHISC, {}, Phi, DL), Name(Name.str()) {
+      : VPSingleDefRecipe(VPRecipeBase::VPWidenPHISC, {}, Phi, DL),
+        Name(Name.str()) {
     if (Start)
       addOperand(Start);
   }
@@ -2323,7 +2442,7 @@ class LLVM_ABI_FOR_TEST VPWidenPHIRecipe : public VPSingleDefRecipe,
 
   ~VPWidenPHIRecipe() override = default;
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenPHISC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenPHISC)
 
   /// Generate the phi/select nodes.
   void execute(VPTransformState &State) override;
@@ -2344,11 +2463,12 @@ class LLVM_ABI_FOR_TEST VPWidenPHIRecipe : public VPSingleDefRecipe,
 struct VPFirstOrderRecurrencePHIRecipe : public VPHeaderPHIRecipe {
   VPFirstOrderRecurrencePHIRecipe(PHINode *Phi, VPValue &Start,
                                   VPValue &BackedgeValue)
-      : VPHeaderPHIRecipe(VPDef::VPFirstOrderRecurrencePHISC, Phi, &Start) {
+      : VPHeaderPHIRecipe(VPRecipeBase::VPFirstOrderRecurrencePHISC, Phi,
+                          &Start) {
     addOperand(&BackedgeValue);
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPFirstOrderRecurrencePHISC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPFirstOrderRecurrencePHISC)
 
   VPFirstOrderRecurrencePHIRecipe *clone() override {
     return new VPFirstOrderRecurrencePHIRecipe(
@@ -2420,8 +2540,8 @@ class VPReductionPHIRecipe : public VPHeaderPHIRecipe,
   VPReductionPHIRecipe(PHINode *Phi, RecurKind Kind, VPValue &Start,
                        VPValue &BackedgeValue, ReductionStyle Style,
                        bool HasUsesOutsideReductionChain = false)
-      : VPHeaderPHIRecipe(VPDef::VPReductionPHISC, Phi, &Start), Kind(Kind),
-        Style(Style),
+      : VPHeaderPHIRecipe(VPRecipeBase::VPReductionPHISC, Phi, &Start),
+        Kind(Kind), Style(Style),
         HasUsesOutsideReductionChain(HasUsesOutsideReductionChain) {
     addOperand(&BackedgeValue);
   }
@@ -2435,7 +2555,7 @@ class VPReductionPHIRecipe : public VPHeaderPHIRecipe,
         HasUsesOutsideReductionChain);
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPReductionPHISC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPReductionPHISC)
 
   /// Generate the phi/select nodes.
   void execute(VPTransformState &State) override;
@@ -2503,7 +2623,7 @@ class LLVM_ABI_FOR_TEST VPBlendRecipe : public VPSingleDefRecipe {
   /// be omitted (implied by passing an odd number of operands) in which case
   /// all other incoming values are merged into it.
   VPBlendRecipe(PHINode *Phi, ArrayRef<VPValue *> Operands, DebugLoc DL)
-      : VPSingleDefRecipe(VPDef::VPBlendSC, Operands, Phi, DL) {
+      : VPSingleDefRecipe(VPRecipeBase::VPBlendSC, Operands, Phi, DL) {
     assert(Operands.size() >= 2 && "Expected at least two operands!");
   }
 
@@ -2512,7 +2632,7 @@ class LLVM_ABI_FOR_TEST VPBlendRecipe : public VPSingleDefRecipe {
                              operands(), getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPBlendSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPBlendSC)
 
   /// A normalized blend is one that has an odd number of operands, whereby the
   /// first operand does not have an associated mask.
@@ -2614,8 +2734,8 @@ class LLVM_ABI_FOR_TEST VPInterleaveBase : public VPRecipeBase,
   VPInterleaveBase *clone() override = 0;
 
   static inline bool classof(const VPRecipeBase *R) {
-    return R->getVPDefID() == VPRecipeBase::VPInterleaveSC ||
-           R->getVPDefID() == VPRecipeBase::VPInterleaveEVLSC;
+    return R->getVPRecipeID() == VPRecipeBase::VPInterleaveSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPInterleaveEVLSC;
   }
 
   static inline bool classof(const VPUser *U) {
@@ -2675,8 +2795,8 @@ class LLVM_ABI_FOR_TEST VPInterleaveRecipe final : public VPInterleaveBase {
   VPInterleaveRecipe(const InterleaveGroup<Instruction> *IG, VPValue *Addr,
                      ArrayRef<VPValue *> StoredValues, VPValue *Mask,
                      bool NeedsMaskForGaps, const VPIRMetadata &MD, DebugLoc DL)
-      : VPInterleaveBase(VPDef::VPInterleaveSC, IG, Addr, StoredValues, Mask,
-                         NeedsMaskForGaps, MD, DL) {}
+      : VPInterleaveBase(VPRecipeBase::VPInterleaveSC, IG, Addr, StoredValues,
+                         Mask, NeedsMaskForGaps, MD, DL) {}
 
   ~VPInterleaveRecipe() override = default;
 
@@ -2686,7 +2806,7 @@ class LLVM_ABI_FOR_TEST VPInterleaveRecipe final : public VPInterleaveBase {
                                   needsMaskForGaps(), *this, getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPInterleaveSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPInterleaveSC)
 
   /// Generate the wide load or store, and shuffles.
   void execute(VPTransformState &State) override;
@@ -2715,10 +2835,10 @@ class LLVM_ABI_FOR_TEST VPInterleaveRecipe final : public VPInterleaveBase {
 class LLVM_ABI_FOR_TEST VPInterleaveEVLRecipe final : public VPInterleaveBase {
 public:
   VPInterleaveEVLRecipe(VPInterleaveRecipe &R, VPValue &EVL, VPValue *Mask)
-      : VPInterleaveBase(VPDef::VPInterleaveEVLSC, R.getInterleaveGroup(),
-                         ArrayRef<VPValue *>({R.getAddr(), &EVL}),
-                         R.getStoredValues(), Mask, R.needsMaskForGaps(), R,
-                         R.getDebugLoc()) {
+      : VPInterleaveBase(
+            VPRecipeBase::VPInterleaveEVLSC, R.getInterleaveGroup(),
+            ArrayRef<VPValue *>({R.getAddr(), &EVL}), R.getStoredValues(), Mask,
+            R.needsMaskForGaps(), R, R.getDebugLoc()) {
     assert(!getInterleaveGroup()->isReverse() &&
            "Reversed interleave-group with tail folding is not supported.");
     assert(!needsMaskForGaps() && "Interleaved access with gap mask is not "
@@ -2731,7 +2851,7 @@ class LLVM_ABI_FOR_TEST VPInterleaveEVLRecipe final : public VPInterleaveBase {
     llvm_unreachable("cloning not implemented yet");
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPInterleaveEVLSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPInterleaveEVLSC)
 
   /// The VPValue of the explicit vector length.
   VPValue *getEVL() const { return getOperand(1); }
@@ -2789,14 +2909,14 @@ class LLVM_ABI_FOR_TEST VPReductionRecipe : public VPRecipeWithIRFlags {
   VPReductionRecipe(RecurKind RdxKind, FastMathFlags FMFs, Instruction *I,
                     VPValue *ChainOp, VPValue *VecOp, VPValue *CondOp,
                     ReductionStyle Style, DebugLoc DL = DebugLoc::getUnknown())
-      : VPReductionRecipe(VPDef::VPReductionSC, RdxKind, FMFs, I,
+      : VPReductionRecipe(VPRecipeBase::VPReductionSC, RdxKind, FMFs, I,
                           ArrayRef<VPValue *>({ChainOp, VecOp}), CondOp, Style,
                           DL) {}
 
   VPReductionRecipe(const RecurKind RdxKind, FastMathFlags FMFs,
                     VPValue *ChainOp, VPValue *VecOp, VPValue *CondOp,
                     ReductionStyle Style, DebugLoc DL = DebugLoc::getUnknown())
-      : VPReductionRecipe(VPDef::VPReductionSC, RdxKind, FMFs, nullptr,
+      : VPReductionRecipe(VPRecipeBase::VPReductionSC, RdxKind, FMFs, nullptr,
                           ArrayRef<VPValue *>({ChainOp, VecOp}), CondOp, Style,
                           DL) {}
 
@@ -2809,8 +2929,8 @@ class LLVM_ABI_FOR_TEST VPReductionRecipe : public VPRecipeWithIRFlags {
   }
 
   static inline bool classof(const VPRecipeBase *R) {
-    return R->getVPDefID() == VPRecipeBase::VPReductionSC ||
-           R->getVPDefID() == VPRecipeBase::VPReductionEVLSC;
+    return R->getVPRecipeID() == VPRecipeBase::VPReductionSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPReductionEVLSC;
   }
 
   static inline bool classof(const VPUser *U) {
@@ -2879,7 +2999,7 @@ class LLVM_ABI_FOR_TEST VPReductionEVLRecipe : public VPReductionRecipe {
   VPReductionEVLRecipe(VPReductionRecipe &R, VPValue &EVL, VPValue *CondOp,
                        DebugLoc DL = DebugLoc::getUnknown())
       : VPReductionRecipe(
-            VPDef::VPReductionEVLSC, R.getRecurrenceKind(),
+            VPRecipeBase::VPReductionEVLSC, R.getRecurrenceKind(),
             R.getFastMathFlags(),
             cast_or_null<Instruction>(R.getUnderlyingValue()),
             ArrayRef<VPValue *>({R.getChainOp(), R.getVecOp(), &EVL}), CondOp,
@@ -2891,7 +3011,7 @@ class LLVM_ABI_FOR_TEST VPReductionEVLRecipe : public VPReductionRecipe {
     llvm_unreachable("cloning not implemented yet");
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPReductionEVLSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPReductionEVLSC)
 
   /// Generate the reduction in the loop
   void execute(VPTransformState &State) override;
@@ -2931,7 +3051,7 @@ class LLVM_ABI_FOR_TEST VPReplicateRecipe : public VPRecipeWithIRFlags,
                     bool IsSingleScalar, VPValue *Mask = nullptr,
                     const VPIRFlags &Flags = {}, VPIRMetadata Metadata = {},
                     DebugLoc DL = DebugLoc::getUnknown())
-      : VPRecipeWithIRFlags(VPDef::VPReplicateSC, Operands, Flags, DL),
+      : VPRecipeWithIRFlags(VPRecipeBase::VPReplicateSC, Operands, Flags, DL),
         VPIRMetadata(Metadata), IsSingleScalar(IsSingleScalar),
         IsPredicated(Mask) {
     setUnderlyingValue(I);
@@ -2949,7 +3069,7 @@ class LLVM_ABI_FOR_TEST VPReplicateRecipe : public VPRecipeWithIRFlags,
     return Copy;
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPReplicateSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPReplicateSC)
 
   /// Generate replicas of the desired Ingredient. Replicas will be generated
   /// for all parts and lanes unless a specific part and lane are specified in
@@ -3003,13 +3123,13 @@ class LLVM_ABI_FOR_TEST VPReplicateRecipe : public VPRecipeWithIRFlags,
 class LLVM_ABI_FOR_TEST VPBranchOnMaskRecipe : public VPRecipeBase {
 public:
   VPBranchOnMaskRecipe(VPValue *BlockInMask, DebugLoc DL)
-      : VPRecipeBase(VPDef::VPBranchOnMaskSC, {BlockInMask}, DL) {}
+      : VPRecipeBase(VPRecipeBase::VPBranchOnMaskSC, {BlockInMask}, DL) {}
 
   VPBranchOnMaskRecipe *clone() override {
     return new VPBranchOnMaskRecipe(getOperand(0), getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPBranchOnMaskSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPBranchOnMaskSC)
 
   /// Generate the extraction of the appropriate bit from the block mask and the
   /// conditional branch.
@@ -3118,7 +3238,7 @@ class VPExpressionRecipe : public VPSingleDefRecipe {
       delete T;
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPExpressionSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPExpressionSC)
 
   VPExpressionRecipe *clone() override {
     assert(!ExpressionRecipes.empty() && "empty expressions should be removed");
@@ -3192,14 +3312,14 @@ class LLVM_ABI_FOR_TEST VPPredInstPHIRecipe : public VPSingleDefRecipe {
   /// Construct a VPPredInstPHIRecipe given \p PredInst whose value needs a phi
   /// nodes after merging back from a Branch-on-Mask.
   VPPredInstPHIRecipe(VPValue *PredV, DebugLoc DL)
-      : VPSingleDefRecipe(VPDef::VPPredInstPHISC, PredV, DL) {}
+      : VPSingleDefRecipe(VPRecipeBase::VPPredInstPHISC, PredV, DL) {}
   ~VPPredInstPHIRecipe() override = default;
 
   VPPredInstPHIRecipe *clone() override {
     return new VPPredInstPHIRecipe(getOperand(0), getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPPredInstPHISC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPPredInstPHISC)
 
   /// Generates phi nodes for live-outs (from a replicate region) as needed to
   /// retain SSA form.
@@ -3272,10 +3392,10 @@ class LLVM_ABI_FOR_TEST VPWidenMemoryRecipe : public VPRecipeBase,
   }
 
   static inline bool classof(const VPRecipeBase *R) {
-    return R->getVPDefID() == VPRecipeBase::VPWidenLoadSC ||
-           R->getVPDefID() == VPRecipeBase::VPWidenStoreSC ||
-           R->getVPDefID() == VPRecipeBase::VPWidenLoadEVLSC ||
-           R->getVPDefID() == VPRecipeBase::VPWidenStoreEVLSC;
+    return R->getVPRecipeID() == VPRecipeBase::VPWidenLoadSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPWidenStoreSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPWidenLoadEVLSC ||
+           R->getVPRecipeID() == VPRecipeBase::VPWidenStoreEVLSC;
   }
 
   static inline bool classof(const VPUser *U) {
@@ -3325,8 +3445,8 @@ struct LLVM_ABI_FOR_TEST VPWidenLoadRecipe final : public VPWidenMemoryRecipe,
   VPWidenLoadRecipe(LoadInst &Load, VPValue *Addr, VPValue *Mask,
                     bool Consecutive, bool Reverse,
                     const VPIRMetadata &Metadata, DebugLoc DL)
-      : VPWidenMemoryRecipe(VPDef::VPWidenLoadSC, Load, {Addr}, Consecutive,
-                            Reverse, Metadata, DL),
+      : VPWidenMemoryRecipe(VPRecipeBase::VPWidenLoadSC, Load, {Addr},
+                            Consecutive, Reverse, Metadata, DL),
         VPRecipeValue(this, &Load) {
     setMask(Mask);
   }
@@ -3337,7 +3457,7 @@ struct LLVM_ABI_FOR_TEST VPWidenLoadRecipe final : public VPWidenMemoryRecipe,
                                  getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenLoadSC);
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenLoadSC);
 
   /// Generate a wide load or gather.
   void execute(VPTransformState &State) override;
@@ -3366,14 +3486,14 @@ struct VPWidenLoadEVLRecipe final : public VPWidenMemoryRecipe,
                                     public VPRecipeValue {
   VPWidenLoadEVLRecipe(VPWidenLoadRecipe &L, VPValue *Addr, VPValue &EVL,
                        VPValue *Mask)
-      : VPWidenMemoryRecipe(VPDef::VPWidenLoadEVLSC, L.getIngredient(),
+      : VPWidenMemoryRecipe(VPRecipeBase::VPWidenLoadEVLSC, L.getIngredient(),
                             {Addr, &EVL}, L.isConsecutive(), L.isReverse(), L,
                             L.getDebugLoc()),
         VPRecipeValue(this, &getIngredient()) {
     setMask(Mask);
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenLoadEVLSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenLoadEVLSC)
 
   /// Return the EVL operand.
   VPValue *getEVL() const { return getOperand(1); }
@@ -3408,8 +3528,9 @@ struct LLVM_ABI_FOR_TEST VPWidenStoreRecipe final : public VPWidenMemoryRecipe {
   VPWidenStoreRecipe(StoreInst &Store, VPValue *Addr, VPValue *StoredVal,
                      VPValue *Mask, bool Consecutive, bool Reverse,
                      const VPIRMetadata &Metadata, DebugLoc DL)
-      : VPWidenMemoryRecipe(VPDef::VPWidenStoreSC, Store, {Addr, StoredVal},
-                            Consecutive, Reverse, Metadata, DL) {
+      : VPWidenMemoryRecipe(VPRecipeBase::VPWidenStoreSC, Store,
+                            {Addr, StoredVal}, Consecutive, Reverse, Metadata,
+                            DL) {
     setMask(Mask);
   }
 
@@ -3419,7 +3540,7 @@ struct LLVM_ABI_FOR_TEST VPWidenStoreRecipe final : public VPWidenMemoryRecipe {
                                   Reverse, *this, getDebugLoc());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenStoreSC);
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenStoreSC);
 
   /// Return the value stored by this recipe.
   VPValue *getStoredValue() const { return getOperand(1); }
@@ -3450,13 +3571,13 @@ struct LLVM_ABI_FOR_TEST VPWidenStoreRecipe final : public VPWidenMemoryRecipe {
 struct VPWidenStoreEVLRecipe final : public VPWidenMemoryRecipe {
   VPWidenStoreEVLRecipe(VPWidenStoreRecipe &S, VPValue *Addr,
                         VPValue *StoredVal, VPValue &EVL, VPValue *Mask)
-      : VPWidenMemoryRecipe(VPDef::VPWidenStoreEVLSC, S.getIngredient(),
+      : VPWidenMemoryRecipe(VPRecipeBase::VPWidenStoreEVLSC, S.getIngredient(),
                             {Addr, StoredVal, &EVL}, S.isConsecutive(),
                             S.isReverse(), S, S.getDebugLoc()) {
     setMask(Mask);
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenStoreEVLSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenStoreEVLSC)
 
   /// Return the address accessed by this recipe.
   VPValue *getStoredValue() const { return getOperand(1); }
@@ -3499,13 +3620,13 @@ class VPExpandSCEVRecipe : public VPSingleDefRecipe {
 
 public:
   VPExpandSCEVRecipe(const SCEV *Expr)
-      : VPSingleDefRecipe(VPDef::VPExpandSCEVSC, {}), Expr(Expr) {}
+      : VPSingleDefRecipe(VPRecipeBase::VPExpandSCEVSC, {}), Expr(Expr) {}
 
   ~VPExpandSCEVRecipe() override = default;
 
   VPExpandSCEVRecipe *clone() override { return new VPExpandSCEVRecipe(Expr); }
 
-  VP_CLASSOF_IMPL(VPDef::VPExpandSCEVSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPExpandSCEVSC)
 
   void execute(VPTransformState &State) override {
     llvm_unreachable("SCEV expressions must be expanded before final execute");
@@ -3535,7 +3656,8 @@ class VPExpandSCEVRecipe : public VPSingleDefRecipe {
 class VPCanonicalIVPHIRecipe : public VPHeaderPHIRecipe {
 public:
   VPCanonicalIVPHIRecipe(VPIRValue *StartV, DebugLoc DL)
-      : VPHeaderPHIRecipe(VPDef::VPCanonicalIVPHISC, nullptr, StartV, DL) {}
+      : VPHeaderPHIRecipe(VPRecipeBase::VPCanonicalIVPHISC, nullptr, StartV,
+                          DL) {}
 
   ~VPCanonicalIVPHIRecipe() override = default;
 
@@ -3545,7 +3667,7 @@ class VPCanonicalIVPHIRecipe : public VPHeaderPHIRecipe {
     return R;
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPCanonicalIVPHISC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPCanonicalIVPHISC)
 
   void execute(VPTransformState &State) override {
     llvm_unreachable("cannot execute this recipe, should be replaced by a "
@@ -3592,8 +3714,8 @@ class VPCanonicalIVPHIRecipe : public VPHeaderPHIRecipe {
 class VPActiveLaneMaskPHIRecipe : public VPHeaderPHIRecipe {
 public:
   VPActiveLaneMaskPHIRecipe(VPValue *StartMask, DebugLoc DL)
-      : VPHeaderPHIRecipe(VPDef::VPActiveLaneMaskPHISC, nullptr, StartMask,
-                          DL) {}
+      : VPHeaderPHIRecipe(VPRecipeBase::VPActiveLaneMaskPHISC, nullptr,
+                          StartMask, DL) {}
 
   ~VPActiveLaneMaskPHIRecipe() override = default;
 
@@ -3604,7 +3726,7 @@ class VPActiveLaneMaskPHIRecipe : public VPHeaderPHIRecipe {
     return R;
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPActiveLaneMaskPHISC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPActiveLaneMaskPHISC)
 
   /// Generate the active lane mask phi of the vector loop.
   void execute(VPTransformState &State) override;
@@ -3624,7 +3746,8 @@ class VPActiveLaneMaskPHIRecipe : public VPHeaderPHIRecipe {
 class VPEVLBasedIVPHIRecipe : public VPHeaderPHIRecipe {
 public:
   VPEVLBasedIVPHIRecipe(VPValue *StartIV, DebugLoc DL)
-      : VPHeaderPHIRecipe(VPDef::VPEVLBasedIVPHISC, nullptr, StartIV, DL) {}
+      : VPHeaderPHIRecipe(VPRecipeBase::VPEVLBasedIVPHISC, nullptr, StartIV,
+                          DL) {}
 
   ~VPEVLBasedIVPHIRecipe() override = default;
 
@@ -3632,7 +3755,7 @@ class VPEVLBasedIVPHIRecipe : public VPHeaderPHIRecipe {
     llvm_unreachable("cloning not implemented yet");
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPEVLBasedIVPHISC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPEVLBasedIVPHISC)
 
   void execute(VPTransformState &State) override {
     llvm_unreachable("cannot execute this recipe, should be replaced by a "
@@ -3666,7 +3789,7 @@ class VPWidenCanonicalIVRecipe : public VPSingleDefRecipe,
                                  public VPUnrollPartAccessor<1> {
 public:
   VPWidenCanonicalIVRecipe(VPCanonicalIVPHIRecipe *CanonicalIV)
-      : VPSingleDefRecipe(VPDef::VPWidenCanonicalIVSC, {CanonicalIV}) {}
+      : VPSingleDefRecipe(VPRecipeBase::VPWidenCanonicalIVSC, {CanonicalIV}) {}
 
   ~VPWidenCanonicalIVRecipe() override = default;
 
@@ -3675,7 +3798,7 @@ class VPWidenCanonicalIVRecipe : public VPSingleDefRecipe,
         cast<VPCanonicalIVPHIRecipe>(getOperand(0)));
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPWidenCanonicalIVSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPWidenCanonicalIVSC)
 
   /// Generate a canonical vector induction variable of the vector loop, with
   /// start = {<Part*VF, Part*VF+1, ..., Part*VF+VF-1> for 0 <= Part < UF}, and
@@ -3722,8 +3845,8 @@ class VPDerivedIVRecipe : public VPSingleDefRecipe {
   VPDerivedIVRecipe(InductionDescriptor::InductionKind Kind,
                     const FPMathOperator *FPBinOp, VPIRValue *Start,
                     VPValue *IV, VPValue *Step, const Twine &Name = "")
-      : VPSingleDefRecipe(VPDef::VPDerivedIVSC, {Start, IV, Step}), Kind(Kind),
-        FPBinOp(FPBinOp), Name(Name.str()) {}
+      : VPSingleDefRecipe(VPRecipeBase::VPDerivedIVSC, {Start, IV, Step}),
+        Kind(Kind), FPBinOp(FPBinOp), Name(Name.str()) {}
 
   ~VPDerivedIVRecipe() override = default;
 
@@ -3732,7 +3855,7 @@ class VPDerivedIVRecipe : public VPSingleDefRecipe {
                                  getStepValue());
   }
 
-  VP_CLASSOF_IMPL(VPDef::VPDerivedIVSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPDerivedIVSC)
 
   /// Generate the transformed value of the induction at offset StartValue (1.
   /// operand) + IV (2. operand) * StepValue (3, operand).
@@ -3775,7 +3898,7 @@ class LLVM_ABI_FOR_TEST VPScalarIVStepsRecipe : public VPRecipeWithIRFlags,
   VPScalarIVStepsRecipe(VPValue *IV, VPValue *Step, VPValue *VF,
                         Instruction::BinaryOps Opcode, FastMathFlags FMFs,
                         DebugLoc DL)
-      : VPRecipeWithIRFlags(VPDef::VPScalarIVStepsSC,
+      : VPRecipeWithIRFlags(VPRecipeBase::VPScalarIVStepsSC,
                             ArrayRef<VPValue *>({IV, Step, VF}), FMFs, DL),
         InductionOpcode(Opcode) {}
 
@@ -3802,7 +3925,7 @@ class LLVM_ABI_FOR_TEST VPScalarIVStepsRecipe : public VPRecipeWithIRFlags,
   /// this is only accurate after the VPlan has been unrolled.
   bool isPart0() const { return getUnrollPart(*this) == 0; }
 
-  VP_CLASSOF_IMPL(VPDef::VPScalarIVStepsSC)
+  VP_CLASSOF_IMPL(VPRecipeBase::VPScalarIVStepsSC)
 
   /// Generate the scalarized versions of the phi node as needed by their users.
   void execute(VPTransformState &State) override;
@@ -3849,12 +3972,12 @@ struct CastInfoVPPhiAccessors : public CastIsPossible<VPPhiAccessors, SrcTy> {
   /// doCast is used by cast<>.
   static inline VPPhiAccessors *doCast(SrcTy R) {
     return const_cast<VPPhiAccessors *>([R]() -> const VPPhiAccessors * {
-      switch (R->getVPDefID()) {
-      case VPDef::VPInstructionSC:
+      switch (R->getVPRecipeID()) {
+      case VPRecipeBase::VPInstructionSC:
         return cast<VPPhi>(R);
-      case VPDef::VPIRInstructionSC:
+      case VPRecipeBase::VPIRInstructionSC:
         return cast<VPIRPhi>(R);
-      case VPDef::VPWidenPHISC:
+      case VPRecipeBase::VPWidenPHISC:
         return cast<VPWidenPHIRecipe>(R);
       default:
         return cast<VPHeaderPHIRecipe>(R);
@@ -3881,26 +4004,26 @@ struct CastInfo<VPPhiAccessors, const VPRecipeBase *>
 namespace detail {
 template <typename DstTy, typename RecipeBasePtrTy>
 static inline auto castToVPIRMetadata(RecipeBasePtrTy R) -> DstTy {
-  switch (R->getVPDefID()) {
-  case VPDef::VPInstructionSC:
+  switch (R->getVPRecipeID()) {
+  case VPRecipeBase::VPInstructionSC:
     return cast<VPInstruction>(R);
-  case VPDef::VPWidenSC:
+  case VPRecipeBase::VPWidenSC:
     return cast<VPWidenRecipe>(R);
-  case VPDef::VPWidenCastSC:
+  case VPRecipeBase::VPWidenCastSC:
     return cast<VPWidenCastRecipe>(R);
-  case VPDef::VPWidenIntrinsicSC:
+  case VPRecipeBase::VPWidenIntrinsicSC:
     return cast<VPWidenIntrinsicRecipe>(R);
-  case VPDef::VPWidenCallSC:
+  case VPRecipeBase::VPWidenCallSC:
     return cast<VPWidenCallRecipe>(R);
-  case VPDef::VPReplicateSC:
+  case VPRecipeBase::VPReplicateSC:
     return cast<VPReplicateRecipe>(R);
-  case VPDef::VPInterleaveSC:
-  case VPDef::VPInterleaveEVLSC:
+  case VPRecipeBase::VPInterleaveSC:
+  case VPRecipeBase::VPInterleaveEVLSC:
     return cast<VPInterleaveBase>(R);
-  case VPDef::VPWidenLoadSC:
-  case VPDef::VPWidenLoadEVLSC:
-  case VPDef::VPWidenStoreSC:
-  case VPDef::VPWidenStoreEVLSC:
+  case VPRecipeBase::VPWidenLoadSC:
+  case VPRecipeBase::VPWidenLoadEVLSC:
+  case VPRecipeBase::VPWidenStoreSC:
+  case VPRecipeBase::VPWidenStoreEVLSC:
     return cast<VPWidenMemoryRecipe>(R);
   default:
     llvm_unreachable("invalid recipe for VPIRMetadata cast");
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index b9cd322d9ec69..df8d134f5eabf 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -48,7 +48,7 @@ using VectorParts = SmallVector<Value *, 2>;
 #define DEBUG_TYPE LV_NAME
 
 bool VPRecipeBase::mayWriteToMemory() const {
-  switch (getVPDefID()) {
+  switch (getVPRecipeID()) {
   case VPExpressionSC:
     return cast<VPExpressionRecipe>(this)->mayReadOrWriteMemory();
   case VPInstructionSC: {
@@ -107,7 +107,7 @@ bool VPRecipeBase::mayWriteToMemory() const {
 }
 
 bool VPRecipeBase::mayReadFromMemory() const {
-  switch (getVPDefID()) {
+  switch (getVPRecipeID()) {
   case VPExpressionSC:
     return cast<VPExpressionRecipe>(this)->mayReadOrWriteMemory();
   case VPInstructionSC:
@@ -157,7 +157,7 @@ bool VPRecipeBase::mayReadFromMemory() const {
 }
 
 bool VPRecipeBase::mayHaveSideEffects() const {
-  switch (getVPDefID()) {
+  switch (getVPRecipeID()) {
   case VPExpressionSC:
     return cast<VPExpressionRecipe>(this)->mayHaveSideEffects();
   case VPDerivedIVSC:
@@ -302,7 +302,7 @@ InstructionCost VPRecipeBase::computeCost(ElementCount VF,
 }
 
 bool VPRecipeBase::isPhi() const {
-  return (getVPDefID() >= VPFirstPHISC && getVPDefID() <= VPLastPHISC) ||
+  return (getVPRecipeID() >= VPFirstPHISC && getVPRecipeID() <= VPLastPHISC) ||
          isa<VPPhi, VPIRPhi>(this);
 }
 
@@ -367,7 +367,7 @@ FastMathFlags VPIRFlags::getFastMathFlags() const {
 }
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-void VPSingleDefRecipe::dump() const { VPDef::dump(); }
+void VPSingleDefRecipe::dump() const { VPRecipeBase::dump(); }
 
 void VPRecipeBase::print(raw_ostream &O, const Twine &Indent,
                          VPSlotTracker &SlotTracker) const {
@@ -406,7 +406,7 @@ template class VPUnrollPartAccessor<3>;
 VPInstruction::VPInstruction(unsigned Opcode, ArrayRef<VPValue *> Operands,
                              const VPIRFlags &Flags, const VPIRMetadata &MD,
                              DebugLoc DL, const Twine &Name)
-    : VPRecipeWithIRFlags(VPDef::VPInstructionSC, Operands, Flags, DL),
+    : VPRecipeWithIRFlags(VPRecipeBase::VPInstructionSC, Operands, Flags, DL),
       VPIRMetadata(MD), Opcode(Opcode), Name(Name.str()) {
   assert(flagsValidForOpcode(getOpcode()) &&
          "Set flags not supported for the provided opcode");
@@ -2788,7 +2788,7 @@ InstructionCost VPReductionRecipe::computeCost(ElementCount VF,
 VPExpressionRecipe::VPExpressionRecipe(
     ExpressionTypes ExpressionType,
     ArrayRef<VPSingleDefRecipe *> ExpressionRecipes)
-    : VPSingleDefRecipe(VPDef::VPExpressionSC, {}, {}),
+    : VPSingleDefRecipe(VPRecipeBase::VPExpressionSC, {}, {}),
       ExpressionRecipes(ExpressionRecipes), ExpressionType(ExpressionType) {
   assert(!ExpressionRecipes.empty() && "Nothing to combine?");
   assert(
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 69541c6618568..59320d1a0f0ad 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1130,9 +1130,9 @@ getOpcodeOrIntrinsicID(const VPSingleDefRecipe *R) {
       .Case<VPVectorPointerRecipe, VPPredInstPHIRecipe>([](auto *I) {
         // For recipes that do not directly map to LLVM IR instructions,
         // assign opcodes after the last VPInstruction opcode (which is also
-        // after the last IR Instruction opcode), based on the VPDefID.
+        // after the last IR Instruction opcode), based on the VPRecipeID.
         return std::make_pair(false,
-                              VPInstruction::OpsEnd + 1 + I->getVPDefID());
+                              VPInstruction::OpsEnd + 1 + I->getVPRecipeID());
       })
       .Default([](auto *) { return std::nullopt; });
 }
@@ -2441,7 +2441,7 @@ struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
     const VPlan *Plan = Def->getParent()->getPlan();
     VPTypeAnalysis TypeInfo(*Plan);
     hash_code Result = hash_combine(
-        Def->getVPDefID(), getOpcodeOrIntrinsicID(Def),
+        Def->getVPRecipeID(), getOpcodeOrIntrinsicID(Def),
         getGEPSourceElementType(Def), TypeInfo.inferScalarType(Def),
         vputils::isSingleScalar(Def), hash_combine_range(Def->operands()));
     if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(Def))
@@ -2454,7 +2454,7 @@ struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
   static bool isEqual(const VPSingleDefRecipe *L, const VPSingleDefRecipe *R) {
     if (isSentinel(L) || isSentinel(R))
       return L == R;
-    if (L->getVPDefID() != R->getVPDefID() ||
+    if (L->getVPRecipeID() != R->getVPRecipeID() ||
         getOpcodeOrIntrinsicID(L) != getOpcodeOrIntrinsicID(R) ||
         getGEPSourceElementType(L) != getGEPSourceElementType(R) ||
         vputils::isSingleScalar(L) != vputils::isSingleScalar(R) ||
diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h
index cae0633dbb185..3187984a1d706 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanValue.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h
@@ -10,9 +10,9 @@
 /// This file contains the declarations of the entities induced by Vectorization
 /// Plans, e.g. the instructions the VPlan intends to generate if executed.
 /// VPlan models the following entities:
-/// VPValue   VPUser   VPDef
-///    |        |
-///   VPInstruction
+/// VPValue   VPUser   VPRecipeBase
+///    |        |         |
+///   VPInstruction ------+
 /// These are documented in docs/VectorizationPlan.rst.
 ///
 //===----------------------------------------------------------------------===//
@@ -32,8 +32,6 @@ namespace llvm {
 class raw_ostream;
 class Type;
 class Value;
-class VPDef;
-struct VPDoubleValueDef;
 class VPSlotTracker;
 class VPUser;
 class VPRecipeBase;
@@ -43,8 +41,6 @@ class VPPhiAccessors;
 /// data flow into, within and out of the VPlan. VPValues can stand for live-ins
 /// coming from the input IR, symbolic values and values defined by recipes.
 class LLVM_ABI_FOR_TEST VPValue {
-  friend class VPDef;
-  friend struct VPDoubleValueDef;
   friend class VPlan;
   friend struct VPIRValue;
   friend struct VPSymbolicValue;
@@ -210,12 +206,12 @@ struct VPSymbolicValue : public VPValue {
 /// A VPValue defined by a recipe that produces one or more values.
 class VPRecipeValue : public VPValue {
   friend class VPValue;
-  friend class VPDef;
-  /// Pointer to the VPDef that defines this VPValue.
-  VPDef *Def;
+  friend class VPRecipeBase;
+  /// Pointer to the VPRecipeBase that defines this VPValue.
+  VPRecipeBase *Def;
 
 public:
-  VPRecipeValue(VPDef *Def, Value *UV = nullptr);
+  VPRecipeValue(VPRecipeBase *Def, Value *UV = nullptr);
 
   virtual ~VPRecipeValue();
 
@@ -324,149 +320,6 @@ class VPUser {
   }
 };
 
-/// This class augments a recipe with a set of VPValues defined by the recipe.
-/// It allows recipes to define zero, one or multiple VPValues. A VPDef owns
-/// the VPValues it defines and is responsible for deleting its defined values.
-/// Single-value VPDefs that also inherit from VPValue must make sure to inherit
-/// from VPDef before VPValue.
-class VPDef {
-  friend class VPValue;
-  friend class VPRecipeValue;
-
-  /// Subclass identifier (for isa/dyn_cast).
-  const unsigned char SubclassID;
-
-  /// The VPValues defined by this VPDef.
-  TinyPtrVector<VPRecipeValue *> DefinedValues;
-
-  /// Add \p V as a defined value by this VPDef.
-  void addDefinedValue(VPRecipeValue *V) {
-    assert(V->Def == this &&
-           "can only add VPValue already linked with this VPDef");
-    DefinedValues.push_back(V);
-  }
-
-  /// Remove \p V from the values defined by this VPDef. \p V must be a defined
-  /// value of this VPDef.
-  void removeDefinedValue(VPRecipeValue *V) {
-    assert(V->Def == this && "can only remove VPValue linked with this VPDef");
-    assert(is_contained(DefinedValues, V) &&
-           "VPValue to remove must be in DefinedValues");
-    llvm::erase(DefinedValues, V);
-    V->Def = nullptr;
-  }
-
-public:
-  /// An enumeration for keeping track of the concrete subclass of VPRecipeBase
-  /// that is actually instantiated. Values of this enumeration are kept in the
-  /// SubclassID field of the VPRecipeBase objects. They are used for concrete
-  /// type identification.
-  using VPRecipeTy = enum {
-    VPBranchOnMaskSC,
-    VPDerivedIVSC,
-    VPExpandSCEVSC,
-    VPExpressionSC,
-    VPIRInstructionSC,
-    VPInstructionSC,
-    VPInterleaveEVLSC,
-    VPInterleaveSC,
-    VPReductionEVLSC,
-    VPReductionSC,
-    VPReplicateSC,
-    VPScalarIVStepsSC,
-    VPVectorPointerSC,
-    VPVectorEndPointerSC,
-    VPWidenCallSC,
-    VPWidenCanonicalIVSC,
-    VPWidenCastSC,
-    VPWidenGEPSC,
-    VPWidenIntrinsicSC,
-    VPWidenLoadEVLSC,
-    VPWidenLoadSC,
-    VPWidenStoreEVLSC,
-    VPWidenStoreSC,
-    VPWidenSC,
-    VPWidenSelectSC,
-    VPBlendSC,
-    VPHistogramSC,
-    // START: Phi-like recipes. Need to be kept together.
-    VPWidenPHISC,
-    VPPredInstPHISC,
-    // START: SubclassID for recipes that inherit VPHeaderPHIRecipe.
-    // VPHeaderPHIRecipe need to be kept together.
-    VPCanonicalIVPHISC,
-    VPActiveLaneMaskPHISC,
-    VPEVLBasedIVPHISC,
-    VPFirstOrderRecurrencePHISC,
-    VPWidenIntOrFpInductionSC,
-    VPWidenPointerInductionSC,
-    VPReductionPHISC,
-    // END: SubclassID for recipes that inherit VPHeaderPHIRecipe
-    // END: Phi-like recipes
-    VPFirstPHISC = VPWidenPHISC,
-    VPFirstHeaderPHISC = VPCanonicalIVPHISC,
-    VPLastHeaderPHISC = VPReductionPHISC,
-    VPLastPHISC = VPReductionPHISC,
-  };
-
-  VPDef(const unsigned char SC) : SubclassID(SC) {}
-
-  virtual ~VPDef() {
-    for (VPRecipeValue *D : to_vector(DefinedValues)) {
-      assert(D->Def == this &&
-             "all defined VPValues should point to the containing VPDef");
-      assert(D->getNumUsers() == 0 &&
-             "all defined VPValues should have no more users");
-      delete D;
-    }
-  }
-
-  /// Returns the only VPValue defined by the VPDef. Can only be called for
-  /// VPDefs with a single defined value.
-  VPValue *getVPSingleValue() {
-    assert(DefinedValues.size() == 1 && "must have exactly one defined value");
-    assert(DefinedValues[0] && "defined value must be non-null");
-    return DefinedValues[0];
-  }
-  const VPValue *getVPSingleValue() const {
-    assert(DefinedValues.size() == 1 && "must have exactly one defined value");
-    assert(DefinedValues[0] && "defined value must be non-null");
-    return DefinedValues[0];
-  }
-
-  /// Returns the VPValue with index \p I defined by the VPDef.
-  VPValue *getVPValue(unsigned I) {
-    assert(DefinedValues[I] && "defined value must be non-null");
-    return DefinedValues[I];
-  }
-  const VPValue *getVPValue(unsigned I) const {
-    assert(DefinedValues[I] && "defined value must be non-null");
-    return DefinedValues[I];
-  }
-
-  /// Returns an ArrayRef of the values defined by the VPDef.
-  ArrayRef<VPRecipeValue *> definedValues() { return DefinedValues; }
-  /// Returns an ArrayRef of the values defined by the VPDef.
-  ArrayRef<VPRecipeValue *> definedValues() const { return DefinedValues; }
-
-  /// Returns the number of values defined by the VPDef.
-  unsigned getNumDefinedValues() const { return DefinedValues.size(); }
-
-  /// \return an ID for the concrete type of this object.
-  /// This is used to implement the classof checks. This should not be used
-  /// for any other purpose, as the values may change as LLVM evolves.
-  unsigned getVPDefID() const { return SubclassID; }
-
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-  /// Dump the VPDef to stderr (for debugging).
-  LLVM_ABI_FOR_TEST void dump() const;
-
-  /// Each concrete VPDef prints itself.
-  virtual void print(raw_ostream &O, const Twine &Indent,
-                     VPSlotTracker &SlotTracker) const = 0;
-#endif
-};
-
 } // namespace llvm
 
 #endif // LLVM_TRANSFORMS_VECTORIZE_VPLAN_VALUE_H
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
index b49c57a1332cf..9b1e7c0af7c8c 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
@@ -1015,7 +1015,7 @@ TEST_F(VPRecipeTest, CastVPWidenRecipeToVPUser) {
   delete AI;
 }
 
-TEST_F(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPDef) {
+TEST_F(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPRecipeBase) {
   VPlan &Plan = getPlan();
   IntegerType *Int32 = IntegerType::get(C, 32);
   FunctionType *FTy = FunctionType::get(Int32, false);
@@ -1056,7 +1056,6 @@ TEST_F(VPRecipeTest, CastVPWidenGEPRecipeToVPUserAndVPDef) {
   checkVPRecipeCastImpl<VPWidenGEPRecipe, VPUser>(&Recipe);
 
   VPValue *VPV = &Recipe;
-  EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDefiningRecipe()));
   EXPECT_EQ(&Recipe, VPV->getDefiningRecipe());
 
   delete GEP;
@@ -1141,7 +1140,7 @@ TEST_F(VPRecipeTest, CastVPBranchOnMaskRecipeToVPUser) {
   checkVPRecipeCastImpl<VPBranchOnMaskRecipe, VPUser>(&Recipe);
 }
 
-TEST_F(VPRecipeTest, CastVPWidenMemoryRecipeToVPUserAndVPDef) {
+TEST_F(VPRecipeTest, CastVPWidenMemoryRecipeToVPUserAndVPRecipeBase) {
   VPlan &Plan = getPlan();
   IntegerType *Int32 = IntegerType::get(C, 32);
   PointerType *Int32Ptr = PointerType::get(C, 0);
@@ -1154,7 +1153,6 @@ TEST_F(VPRecipeTest, CastVPWidenMemoryRecipeToVPUserAndVPDef) {
   checkVPRecipeCastImpl<VPWidenLoadRecipe, VPUser, VPIRMetadata>(&Recipe);
 
   VPValue *VPV = Recipe.getVPSingleValue();
-  EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDefiningRecipe()));
   EXPECT_EQ(&Recipe, VPV->getDefiningRecipe());
 
   delete Load;
@@ -1432,7 +1430,7 @@ TEST_F(VPRecipeTest, dumpRecipeInPlan) {
         },
         testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
 
-    VPDef *Def = WidenR;
+    VPRecipeBase *Def = WidenR;
     EXPECT_EXIT(
         {
           Def->dump();
@@ -1455,15 +1453,6 @@ TEST_F(VPRecipeTest, dumpRecipeInPlan) {
           exit(0);
         },
         testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
-
-    // Test VPDef::dump().
-    VPDef *D = WidenR;
-    EXPECT_EXIT(
-        {
-          D->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
   }
 
   delete AI;
@@ -1511,15 +1500,6 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesInPlan) {
           exit(0);
         },
         testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
-
-    // Test VPDef::dump().
-    VPDef *D = I1;
-    EXPECT_EXIT(
-        {
-          D->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
   }
   // Check printing I2.
   {
@@ -1542,15 +1522,6 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesInPlan) {
           exit(0);
         },
         testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
-
-    // Test VPDef::dump().
-    VPDef *D = I2;
-    EXPECT_EXIT(
-        {
-          D->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
   }
   delete AI;
 }
@@ -1587,15 +1558,6 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
           exit(0);
         },
         testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
-
-    // Test VPDef::dump().
-    VPDef *D = I1;
-    EXPECT_EXIT(
-        {
-          D->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
   }
   // Check printing I2.
   {
@@ -1618,15 +1580,6 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
           exit(0);
         },
         testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
-
-    // Test VPDef::dump().
-    VPDef *D = I2;
-    EXPECT_EXIT(
-        {
-          D->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
   }
 
   delete I2;
@@ -1683,7 +1636,7 @@ TEST(VPDoubleValueDefTest, traverseUseLists) {
   // Check that the def-use chains of a multi-def can be traversed in both
   // directions.
 
-  // Create a new VPDef which defines 2 values and has 2 operands.
+  // Create a new VPRecipeBase which defines 2 values and has 2 operands.
   VPInstruction Op0(VPInstruction::StepVector, {});
   VPInstruction Op1(VPInstruction::VScale, {});
   VPDoubleValueDef DoubleValueDef({&Op0, &Op1});
@@ -1694,7 +1647,7 @@ TEST(VPDoubleValueDefTest, traverseUseLists) {
   VPInstruction I2(Instruction::Freeze, {DoubleValueDef.getVPValue(0)});
   VPInstruction I3(Instruction::Freeze, {DoubleValueDef.getVPValue(1)});
 
-  // Check operands of the VPDef (traversing upwards).
+  // Check operands of the VPRecipeBase (traversing upwards).
   SmallVector<VPValue *, 4> DoubleOperands(DoubleValueDef.op_begin(),
                                            DoubleValueDef.op_end());
   EXPECT_EQ(2u, DoubleOperands.size());
@@ -1716,7 +1669,7 @@ TEST(VPDoubleValueDefTest, traverseUseLists) {
   EXPECT_EQ(&I1, DoubleValueDefV1Users[0]);
   EXPECT_EQ(&I3, DoubleValueDefV1Users[1]);
 
-  // Now check that we can get the right VPDef for each defined value.
+  // Now check that we can get the right VPRecipeBase for each defined value.
   EXPECT_EQ(&DoubleValueDef, I1.getOperand(0)->getDefiningRecipe());
   EXPECT_EQ(&DoubleValueDef, I1.getOperand(1)->getDefiningRecipe());
   EXPECT_EQ(&DoubleValueDef, I2.getOperand(0)->getDefiningRecipe());

>From a98f1edca1b30d546d41b0b66e32ebf644692e8e Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 9 Jan 2026 20:57:10 +0000
Subject: [PATCH 2/3] !fixup address comments, restore VPDef for now

---
 llvm/lib/Transforms/Vectorize/VPlan.cpp    |  8 +--
 llvm/lib/Transforms/Vectorize/VPlan.h      | 59 ++++-------------
 llvm/lib/Transforms/Vectorize/VPlanValue.h | 74 +++++++++++++++++++++-
 3 files changed, 87 insertions(+), 54 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 5f050627a1fbc..c78e622e50ad0 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -116,16 +116,12 @@ void VPRecipeBase::dump() const {
 
 VPRecipeBase *VPValue::getDefiningRecipe() {
   auto *DefValue = dyn_cast<VPRecipeValue>(this);
-  if (!DefValue)
-    return nullptr;
-  return DefValue->Def;
+  return DefValue ? DefValue->Def : nullptr;
 }
 
 const VPRecipeBase *VPValue::getDefiningRecipe() const {
   auto *DefValue = dyn_cast<VPRecipeValue>(this);
-  if (!DefValue)
-    return nullptr;
-  return DefValue->Def;
+  return DefValue ? DefValue->Def : nullptr;
 }
 
 Value *VPValue::getLiveInIRValue() const {
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index c054be345d008..4325f7f205722 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -377,12 +377,13 @@ class LLVM_ABI_FOR_TEST VPBlockBase {
 };
 
 /// VPRecipeBase is a base class modeling a sequence of one or more output IR
-/// instructions. VPRecipeBase owns the VPValues it defines and is responsible
-/// for deleting its defined values. Single-value recipes must inherit from
-/// VPSingleDefRecipe instead of inheriting from both VPRecipeBase and VPValue
-/// separately.
+/// instructions. VPRecipeBase owns the VPValues it defines through VPDef
+/// and is responsible for deleting its defined values. Single-value recipes
+/// must inherit from VPSingleDefRecipe instead of inheriting from both
+/// VPRecipeBase and VPValue separately.
 class LLVM_ABI_FOR_TEST VPRecipeBase
     : public ilist_node_with_parent<VPRecipeBase, VPBasicBlock>,
+      public VPDef,
       public VPUser {
   friend VPBasicBlock;
   friend class VPBlockUtils;
@@ -394,12 +395,6 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
   /// The debug location for the recipe.
   DebugLoc DL;
 
-  /// Subclass identifier (for isa/dyn_cast).
-  const unsigned char SubclassID;
-
-  /// The VPValues defined by this VPRecipeBase.
-  TinyPtrVector<VPRecipeValue *> DefinedValues;
-
   /// Add \p V as a defined value by this VPRecipeBase.
   void addDefinedValue(VPRecipeValue *V) {
     assert(V->Def == this &&
@@ -473,9 +468,9 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
 
   VPRecipeBase(const unsigned char SC, ArrayRef<VPValue *> Operands,
                DebugLoc DL = DebugLoc::getUnknown())
-      : VPUser(Operands), DL(DL), SubclassID(SC) {}
+      : VPDef(SC), VPUser(Operands), DL(DL) {}
 
-  virtual ~VPRecipeBase() {
+  ~VPRecipeBase() override {
     for (VPRecipeValue *D : to_vector(DefinedValues)) {
       assert(
           D->Def == this &&
@@ -486,41 +481,10 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
     }
   }
 
-  /// Returns the only VPValue defined by the VPRecipeBase. Can only be called
-  /// for VPRecipeBases with a single defined value.
-  VPValue *getVPSingleValue() {
-    assert(DefinedValues.size() == 1 && "must have exactly one defined value");
-    assert(DefinedValues[0] && "defined value must be non-null");
-    return DefinedValues[0];
-  }
-  const VPValue *getVPSingleValue() const {
-    assert(DefinedValues.size() == 1 && "must have exactly one defined value");
-    assert(DefinedValues[0] && "defined value must be non-null");
-    return DefinedValues[0];
-  }
-
-  /// Returns the VPValue with index \p I defined by the VPRecipeBase.
-  VPValue *getVPValue(unsigned I) {
-    assert(DefinedValues[I] && "defined value must be non-null");
-    return DefinedValues[I];
-  }
-  const VPValue *getVPValue(unsigned I) const {
-    assert(DefinedValues[I] && "defined value must be non-null");
-    return DefinedValues[I];
-  }
-
-  /// Returns an ArrayRef of the values defined by the VPRecipeBase.
-  ArrayRef<VPRecipeValue *> definedValues() { return DefinedValues; }
-  /// Returns an ArrayRef of the values defined by the VPRecipeBase.
-  ArrayRef<VPRecipeValue *> definedValues() const { return DefinedValues; }
-
-  /// Returns the number of values defined by the VPRecipeBase.
-  unsigned getNumDefinedValues() const { return DefinedValues.size(); }
-
   /// \return an ID for the concrete type of this object.
   /// This is used to implement the classof checks. This should not be used
   /// for any other purpose, as the values may change as LLVM evolves.
-  unsigned getVPRecipeID() const { return SubclassID; }
+  unsigned getVPRecipeID() const { return getVPDefID(); }
 
   /// Clone the current recipe.
   virtual VPRecipeBase *clone() = 0;
@@ -572,6 +536,11 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
   iplist<VPRecipeBase>::iterator eraseFromParent();
 
   /// Method to support type inquiry through isa, cast, and dyn_cast.
+  static inline bool classof(const VPDef *D) {
+    // All VPDefs are also VPRecipeBases.
+    return true;
+  }
+
   static inline bool classof(const VPUser *U) { return true; }
 
   /// Returns true if the recipe may have side-effects.
@@ -606,7 +575,7 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
 
   /// Print the recipe, delegating to printRecipe().
   void print(raw_ostream &O, const Twine &Indent,
-             VPSlotTracker &SlotTracker) const;
+             VPSlotTracker &SlotTracker) const override final;
 #endif
 
 protected:
diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h
index 3187984a1d706..9124864c20962 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanValue.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h
@@ -10,9 +10,9 @@
 /// This file contains the declarations of the entities induced by Vectorization
 /// Plans, e.g. the instructions the VPlan intends to generate if executed.
 /// VPlan models the following entities:
-/// VPValue   VPUser   VPRecipeBase
-///    |        |         |
-///   VPInstruction ------+
+/// VPValue   VPUser   VPDef
+///    |        |        |
+///   VPInstruction -----+
 /// These are documented in docs/VectorizationPlan.rst.
 ///
 //===----------------------------------------------------------------------===//
@@ -33,6 +33,7 @@ class raw_ostream;
 class Type;
 class Value;
 class VPSlotTracker;
+class VPDef;
 class VPUser;
 class VPRecipeBase;
 class VPPhiAccessors;
@@ -41,6 +42,7 @@ class VPPhiAccessors;
 /// data flow into, within and out of the VPlan. VPValues can stand for live-ins
 /// coming from the input IR, symbolic values and values defined by recipes.
 class LLVM_ABI_FOR_TEST VPValue {
+  friend class VPDef;
   friend class VPlan;
   friend struct VPIRValue;
   friend struct VPSymbolicValue;
@@ -206,6 +208,7 @@ struct VPSymbolicValue : public VPValue {
 /// A VPValue defined by a recipe that produces one or more values.
 class VPRecipeValue : public VPValue {
   friend class VPValue;
+  friend class VPDef;
   friend class VPRecipeBase;
   /// Pointer to the VPRecipeBase that defines this VPValue.
   VPRecipeBase *Def;
@@ -320,6 +323,71 @@ class VPUser {
   }
 };
 
+/// This class augments a recipe with a set of VPValues defined by the recipe.
+/// It allows recipes to define zero, one or multiple VPValues. A VPDef owns
+/// the VPValues it defines and is responsible for deleting its defined values.
+/// Single-value VPDefs that also inherit from VPValue must make sure to inherit
+/// from VPDef before VPValue.
+class VPDef {
+  friend class VPRecipeBase;
+
+  /// Subclass identifier (for isa/dyn_cast).
+  const unsigned char SubclassID;
+
+  /// The VPValues defined by this VPDef.
+  TinyPtrVector<VPRecipeValue *> DefinedValues;
+
+public:
+  VPDef(const unsigned char SC) : SubclassID(SC) {}
+
+  virtual ~VPDef() = default;
+
+  /// Returns the only VPValue defined by the VPDef. Can only be called for
+  /// VPDefs with a single defined value.
+  VPValue *getVPSingleValue() {
+    assert(DefinedValues.size() == 1 && "must have exactly one defined value");
+    assert(DefinedValues[0] && "defined value must be non-null");
+    return DefinedValues[0];
+  }
+  const VPValue *getVPSingleValue() const {
+    assert(DefinedValues.size() == 1 && "must have exactly one defined value");
+    assert(DefinedValues[0] && "defined value must be non-null");
+    return DefinedValues[0];
+  }
+
+  /// Returns the VPValue with index \p I defined by the VPDef.
+  VPValue *getVPValue(unsigned I) {
+    assert(DefinedValues[I] && "defined value must be non-null");
+    return DefinedValues[I];
+  }
+  const VPValue *getVPValue(unsigned I) const {
+    assert(DefinedValues[I] && "defined value must be non-null");
+    return DefinedValues[I];
+  }
+
+  /// Returns an ArrayRef of the values defined by the VPDef.
+  ArrayRef<VPRecipeValue *> definedValues() { return DefinedValues; }
+  /// Returns an ArrayRef of the values defined by the VPDef.
+  ArrayRef<VPRecipeValue *> definedValues() const { return DefinedValues; }
+
+  /// Returns the number of values defined by the VPDef.
+  unsigned getNumDefinedValues() const { return DefinedValues.size(); }
+
+  /// \return an ID for the concrete type of this object.
+  /// This is used to implement the classof checks. This should not be used
+  /// for any other purpose, as the values may change as LLVM evolves.
+  unsigned getVPDefID() const { return SubclassID; }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  /// Dump the VPDef to stderr (for debugging).
+  LLVM_ABI_FOR_TEST void dump() const;
+
+  /// Each concrete VPDef prints itself.
+  virtual void print(raw_ostream &O, const Twine &Indent,
+                     VPSlotTracker &SlotTracker) const = 0;
+#endif
+};
+
 } // namespace llvm
 
 #endif // LLVM_TRANSFORMS_VECTORIZE_VPLAN_VALUE_H

>From f4abb0f7eac7c8bfa78fbd3aa93fdf4ffe766c33 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 11 Jan 2026 16:56:02 +0000
Subject: [PATCH 3/3] !fixup restore VPDef class as much as possible

---
 llvm/docs/VectorizationPlan.rst            |  8 +++--
 llvm/lib/Transforms/Vectorize/VPlan.cpp    |  2 ++
 llvm/lib/Transforms/Vectorize/VPlan.h      | 30 +---------------
 llvm/lib/Transforms/Vectorize/VPlanValue.h | 41 ++++++++++++++++++----
 4 files changed, 44 insertions(+), 37 deletions(-)

diff --git a/llvm/docs/VectorizationPlan.rst b/llvm/docs/VectorizationPlan.rst
index b8db8cab843cf..73e9e6098175a 100644
--- a/llvm/docs/VectorizationPlan.rst
+++ b/llvm/docs/VectorizationPlan.rst
@@ -186,8 +186,7 @@ The low-level design of VPlan comprises of the following classes.
   input IR instructions are referred to as "Ingredients" of the Recipe. A Recipe
   may specify how its ingredients are to be transformed to produce the output IR
   instructions; e.g., cloned once, replicated multiple times or widened
-  according to selected VF. VPRecipeBase also defines zero, one or multiple
-  VPValues, modeling the fact that recipes can produce multiple results.
+  according to selected VF.
 
 :VPValue:
   The base of VPlan's def-use relations class hierarchy. When instantiated, it
@@ -198,6 +197,11 @@ The low-level design of VPlan comprises of the following classes.
   A VPUser represents an entity that uses a number of VPValues as operands.
   VPUser is similar in some aspects to LLVM's User class.
 
+:VPDef:
+  A VPDef represents an entity that defines zero, one or multiple VPValues.
+  It is used to model the fact that recipes in VPlan can define multiple
+  VPValues.
+
 :VPInstruction:
   A VPInstruction is a recipe characterized by a single opcode and optional
   flags, free of ingredients or other meta-data. VPInstructions also extend
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index c78e622e50ad0..6cd828e8c2db8 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -114,6 +114,8 @@ void VPRecipeBase::dump() const {
 }
 #endif
 
+bool VPRecipeValue::isDefinedBy(const VPDef *D) const { return Def == D; }
+
 VPRecipeBase *VPValue::getDefiningRecipe() {
   auto *DefValue = dyn_cast<VPRecipeValue>(this);
   return DefValue ? DefValue->Def : nullptr;
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 17aa4f081f5a1..2c0efb71d7d0e 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -387,7 +387,6 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
       public VPUser {
   friend VPBasicBlock;
   friend class VPBlockUtils;
-  friend class VPRecipeValue;
 
   /// Each VPRecipe belongs to a single VPBasicBlock.
   VPBasicBlock *Parent = nullptr;
@@ -395,24 +394,6 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
   /// The debug location for the recipe.
   DebugLoc DL;
 
-  /// Add \p V as a defined value by this VPRecipeBase.
-  void addDefinedValue(VPRecipeValue *V) {
-    assert(V->Def == this &&
-           "can only add VPValue already linked with this VPRecipeBase");
-    DefinedValues.push_back(V);
-  }
-
-  /// Remove \p V from the values defined by this VPRecipeBase. \p V must be a
-  /// defined value of this VPRecipeBase.
-  void removeDefinedValue(VPRecipeValue *V) {
-    assert(V->Def == this &&
-           "can only remove VPValue linked with this VPRecipeBase");
-    assert(is_contained(DefinedValues, V) &&
-           "VPValue to remove must be in DefinedValues");
-    llvm::erase(DefinedValues, V);
-    V->Def = nullptr;
-  }
-
 public:
   /// An enumeration for keeping track of the concrete subclass of VPRecipeBase
   /// that is actually instantiated. Values of this enumeration are kept in the
@@ -470,16 +451,7 @@ class LLVM_ABI_FOR_TEST VPRecipeBase
                DebugLoc DL = DebugLoc::getUnknown())
       : VPDef(SC), VPUser(Operands), DL(DL) {}
 
-  ~VPRecipeBase() override {
-    for (VPRecipeValue *D : to_vector(DefinedValues)) {
-      assert(
-          D->Def == this &&
-          "all defined VPValues should point to the containing VPRecipeBase");
-      assert(D->getNumUsers() == 0 &&
-             "all defined VPValues should have no more users");
-      delete D;
-    }
-  }
+  ~VPRecipeBase() override = default;
 
   /// \return an ID for the concrete type of this object.
   /// This is used to implement the classof checks. This should not be used
diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h
index 9124864c20962..aefc94a3c0bea 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanValue.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h
@@ -11,8 +11,8 @@
 /// Plans, e.g. the instructions the VPlan intends to generate if executed.
 /// VPlan models the following entities:
 /// VPValue   VPUser   VPDef
-///    |        |        |
-///   VPInstruction -----+
+///    |        |
+///   VPInstruction
 /// These are documented in docs/VectorizationPlan.rst.
 ///
 //===----------------------------------------------------------------------===//
@@ -209,10 +209,12 @@ struct VPSymbolicValue : public VPValue {
 class VPRecipeValue : public VPValue {
   friend class VPValue;
   friend class VPDef;
-  friend class VPRecipeBase;
-  /// Pointer to the VPRecipeBase that defines this VPValue.
+  /// Pointer to the VPDef that defines this VPValue.
   VPRecipeBase *Def;
 
+  /// Returns true if this VPRecipeValue is defined by \p D.
+  bool isDefinedBy(const VPDef *D) const;
+
 public:
   VPRecipeValue(VPRecipeBase *Def, Value *UV = nullptr);
 
@@ -329,7 +331,8 @@ class VPUser {
 /// Single-value VPDefs that also inherit from VPValue must make sure to inherit
 /// from VPDef before VPValue.
 class VPDef {
-  friend class VPRecipeBase;
+  friend class VPValue;
+  friend class VPRecipeValue;
 
   /// Subclass identifier (for isa/dyn_cast).
   const unsigned char SubclassID;
@@ -337,10 +340,36 @@ class VPDef {
   /// The VPValues defined by this VPDef.
   TinyPtrVector<VPRecipeValue *> DefinedValues;
 
+  /// Add \p V as a defined value by this VPDef.
+  void addDefinedValue(VPRecipeValue *V) {
+    assert(V->isDefinedBy(this) &&
+           "can only add VPValue already linked with this VPDef");
+    DefinedValues.push_back(V);
+  }
+
+  /// Remove \p V from the values defined by this VPDef. \p V must be a defined
+  /// value of this VPDef.
+  void removeDefinedValue(VPRecipeValue *V) {
+    assert(V->isDefinedBy(this) &&
+           "can only remove VPValue linked with this VPDef");
+    assert(is_contained(DefinedValues, V) &&
+           "VPValue to remove must be in DefinedValues");
+    llvm::erase(DefinedValues, V);
+    V->Def = nullptr;
+  }
+
 public:
   VPDef(const unsigned char SC) : SubclassID(SC) {}
 
-  virtual ~VPDef() = default;
+  virtual ~VPDef() {
+    for (VPRecipeValue *D : to_vector(DefinedValues)) {
+      assert(D->isDefinedBy(this) &&
+             "all defined VPValues should point to the containing VPDef");
+      assert(D->getNumUsers() == 0 &&
+             "all defined VPValues should have no more users");
+      delete D;
+    }
+  }
 
   /// Returns the only VPValue defined by the VPDef. Can only be called for
   /// VPDefs with a single defined value.



More information about the llvm-commits mailing list