Skip to content

[VPlan] Manage instruction metadata in VPlan. #135272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 24, 2025
Merged

Conversation

fhahn
Copy link
Contributor

@fhahn fhahn commented Apr 10, 2025

Add a new helper to manage IR metadata that can be progated to generated instructions for recipes.

This helps to remove a number of remaining uses of getUnderlyingInstr during VPlan execution.

@llvmbot
Copy link
Member

llvmbot commented Apr 10, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

Changes

Add a new helper to manage IR metadata that can be progated to generated instructions for recipes.

This helps to remove a number of remaining uses of getUnderlyingInstr during VPlan execution.


Full diff: https://github.com/llvm/llvm-project/pull/135272.diff

4 Files Affected:

  • (modified) llvm/lib/Transforms/Vectorize/VPlan.cpp (+5-15)
  • (modified) llvm/lib/Transforms/Vectorize/VPlan.h (+35-17)
  • (modified) llvm/lib/Transforms/Vectorize/VPlanHelpers.h (+1-8)
  • (modified) llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp (+24-11)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 9474e7a171dff..229949725128a 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -356,23 +356,13 @@ BasicBlock *VPTransformState::CFGState::getPreheaderBBFor(VPRecipeBase *R) {
   return VPBB2IRBB[LoopRegion->getPreheaderVPBB()];
 }
 
-void VPTransformState::addNewMetadata(Instruction *To,
-                                      const Instruction *Orig) {
+void VPTransformState::addNewMetadata(Value *To, const Instruction *Orig) {
+
   // If the loop was versioned with memchecks, add the corresponding no-alias
   // metadata.
-  if (LVer && isa<LoadInst, StoreInst>(Orig))
-    LVer->annotateInstWithNoAlias(To, Orig);
-}
-
-void VPTransformState::addMetadata(Value *To, Instruction *From) {
-  // No source instruction to transfer metadata from?
-  if (!From)
-    return;
-
-  if (Instruction *ToI = dyn_cast<Instruction>(To)) {
-    propagateMetadata(ToI, From);
-    addNewMetadata(ToI, From);
-  }
+  Instruction *ToI = dyn_cast<Instruction>(To);
+  if (ToI && LVer && isa<LoadInst, StoreInst>(Orig))
+    LVer->annotateInstWithNoAlias(ToI, Orig);
 }
 
 void VPTransformState::setDebugLocFrom(DebugLoc DL) {
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 669e8f371d3d3..11f637f7b1518 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1114,18 +1114,33 @@ struct VPIRPhi : public VPIRInstruction {
 #endif
 };
 
+/// Helper to manage IR metadata for recipes. It filters out metadata that
+/// cannot be proagated.
+class VPWithIRMetadata {
+  SmallVector<std::pair<unsigned, MDNode *>> Metadata;
+
+public:
+  VPWithIRMetadata() {}
+
+  VPWithIRMetadata(Instruction &I) { getMetadataToPropagate(&I, Metadata); }
+
+  /// Add all metadata to \p V if it is an instruction.
+  void setMetadata(Value *V) const;
+};
+
 /// VPWidenRecipe is a recipe for producing a widened instruction using the
 /// opcode and operands of the recipe. This recipe covers most of the
 /// traditional vectorization cases where each recipe transforms into a
 /// vectorized version of itself.
-class VPWidenRecipe : public VPRecipeWithIRFlags {
+class VPWidenRecipe : public VPRecipeWithIRFlags, public VPWithIRMetadata {
   unsigned Opcode;
 
 protected:
   template <typename IterT>
   VPWidenRecipe(unsigned VPDefOpcode, Instruction &I,
                 iterator_range<IterT> Operands)
-      : VPRecipeWithIRFlags(VPDefOpcode, Operands, I), Opcode(I.getOpcode()) {}
+      : VPRecipeWithIRFlags(VPDefOpcode, Operands, I), VPWithIRMetadata(I),
+        Opcode(I.getOpcode()) {}
 
 public:
   template <typename IterT>
@@ -1160,7 +1175,7 @@ class VPWidenRecipe : public VPRecipeWithIRFlags {
 };
 
 /// VPWidenCastRecipe is a recipe to create vector cast instructions.
-class VPWidenCastRecipe : public VPRecipeWithIRFlags {
+class VPWidenCastRecipe : public VPRecipeWithIRFlags, public VPWithIRMetadata {
   /// Cast instruction opcode.
   Instruction::CastOps Opcode;
 
@@ -1170,15 +1185,15 @@ class VPWidenCastRecipe : public VPRecipeWithIRFlags {
 public:
   VPWidenCastRecipe(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy,
                     CastInst &UI)
-      : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op, UI), Opcode(Opcode),
-        ResultTy(ResultTy) {
+      : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op, UI), VPWithIRMetadata(UI),
+        Opcode(Opcode), ResultTy(ResultTy) {
     assert(UI.getOpcode() == Opcode &&
            "opcode of underlying cast doesn't match");
   }
 
   VPWidenCastRecipe(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy)
-      : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op), Opcode(Opcode),
-        ResultTy(ResultTy) {}
+      : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op), VPWithIRMetadata(),
+        Opcode(Opcode), ResultTy(ResultTy) {}
 
   ~VPWidenCastRecipe() override = default;
 
@@ -1260,7 +1275,8 @@ class VPScalarCastRecipe : public VPSingleDefRecipe {
 };
 
 /// A recipe for widening vector intrinsics.
-class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags {
+class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags,
+                               public VPWithIRMetadata {
   /// ID of the vector intrinsic to widen.
   Intrinsic::ID VectorIntrinsicID;
 
@@ -1281,8 +1297,8 @@ class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags {
                          ArrayRef<VPValue *> CallArguments, Type *Ty,
                          DebugLoc DL = {})
       : VPRecipeWithIRFlags(VPDef::VPWidenIntrinsicSC, CallArguments, CI),
-        VectorIntrinsicID(VectorIntrinsicID), ResultTy(Ty),
-        MayReadFromMemory(CI.mayReadFromMemory()),
+        VPWithIRMetadata(CI), VectorIntrinsicID(VectorIntrinsicID),
+        ResultTy(Ty), MayReadFromMemory(CI.mayReadFromMemory()),
         MayWriteToMemory(CI.mayWriteToMemory()),
         MayHaveSideEffects(CI.mayHaveSideEffects()) {}
 
@@ -1346,7 +1362,7 @@ class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags {
 };
 
 /// A recipe for widening Call instructions using library calls.
-class VPWidenCallRecipe : public VPRecipeWithIRFlags {
+class VPWidenCallRecipe : public VPRecipeWithIRFlags, public VPWithIRMetadata {
   /// Variant stores a pointer to the chosen function. There is a 1:1 mapping
   /// between a given VF and the chosen vectorized variant, so there will be a
   /// different VPlan for each VF with a valid variant.
@@ -1357,7 +1373,7 @@ class VPWidenCallRecipe : public VPRecipeWithIRFlags {
                     ArrayRef<VPValue *> CallArguments, DebugLoc DL = {})
       : VPRecipeWithIRFlags(VPDef::VPWidenCallSC, CallArguments,
                             *cast<Instruction>(UV)),
-        Variant(Variant) {
+        VPWithIRMetadata(*cast<Instruction>(UV)), Variant(Variant) {
     assert(
         isa<Function>(getOperand(getNumOperands() - 1)->getLiveInIRValue()) &&
         "last operand must be the called function");
@@ -1443,10 +1459,12 @@ class VPHistogramRecipe : public VPRecipeBase {
 };
 
 /// A recipe for widening select instructions.
-struct VPWidenSelectRecipe : public VPRecipeWithIRFlags {
+struct VPWidenSelectRecipe : public VPRecipeWithIRFlags,
+                             public VPWithIRMetadata {
   template <typename IterT>
   VPWidenSelectRecipe(SelectInst &I, iterator_range<IterT> Operands)
-      : VPRecipeWithIRFlags(VPDef::VPWidenSelectSC, Operands, I) {}
+      : VPRecipeWithIRFlags(VPDef::VPWidenSelectSC, Operands, I),
+        VPWithIRMetadata(I) {}
 
   ~VPWidenSelectRecipe() override = default;
 
@@ -2564,7 +2582,7 @@ class VPPredInstPHIRecipe : public VPSingleDefRecipe {
 
 /// A common base class for widening memory operations. An optional mask can be
 /// provided as the last operand.
-class VPWidenMemoryRecipe : public VPRecipeBase {
+class VPWidenMemoryRecipe : public VPRecipeBase, public VPWithIRMetadata {
 protected:
   Instruction &Ingredient;
 
@@ -2588,8 +2606,8 @@ class VPWidenMemoryRecipe : public VPRecipeBase {
   VPWidenMemoryRecipe(const char unsigned SC, Instruction &I,
                       std::initializer_list<VPValue *> Operands,
                       bool Consecutive, bool Reverse, DebugLoc DL)
-      : VPRecipeBase(SC, Operands, DL), Ingredient(I), Consecutive(Consecutive),
-        Reverse(Reverse) {
+      : VPRecipeBase(SC, Operands, DL), VPWithIRMetadata(I), Ingredient(I),
+        Consecutive(Consecutive), Reverse(Reverse) {
     assert((Consecutive || !Reverse) && "Reverse implies consecutive");
   }
 
diff --git a/llvm/lib/Transforms/Vectorize/VPlanHelpers.h b/llvm/lib/Transforms/Vectorize/VPlanHelpers.h
index bebea1915690f..4826dfd562c2d 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanHelpers.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanHelpers.h
@@ -288,14 +288,7 @@ struct VPTransformState {
   /// Currently this is used to add the noalias annotations based on the
   /// inserted memchecks.  Use this for instructions that are *cloned* into the
   /// vector loop.
-  void addNewMetadata(Instruction *To, const Instruction *Orig);
-
-  /// Add metadata from one instruction to another.
-  ///
-  /// This includes both the original MDs from \p From and additional ones (\see
-  /// addNewMetadata).  Use this for *newly created* instructions in the vector
-  /// loop.
-  void addMetadata(Value *To, Instruction *From);
+  void addNewMetadata(Value *To, const Instruction *Orig);
 
   /// Set the debug location in the builder using the debug location \p DL.
   void setDebugLocFrom(DebugLoc DL);
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 35e141ed01267..077867cbc7a92 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1159,6 +1159,14 @@ void VPIRPhi::print(raw_ostream &O, const Twine &Indent,
 }
 #endif
 
+void VPWithIRMetadata::setMetadata(Value *V) const {
+  auto *I = dyn_cast<Instruction>(V);
+  if (!I)
+    return;
+  for (const auto &[Kind, Node] : Metadata)
+    I->setMetadata(Kind, Node);
+}
+
 void VPWidenCallRecipe::execute(VPTransformState &State) {
   assert(State.VF.isVector() && "not widening");
 
@@ -1189,7 +1197,7 @@ void VPWidenCallRecipe::execute(VPTransformState &State) {
 
   if (!V->getType()->isVoidTy())
     State.set(this, V);
-  State.addMetadata(V, CI);
+  setMetadata(V);
 }
 
 InstructionCost VPWidenCallRecipe::computeCost(ElementCount VF,
@@ -1268,7 +1276,7 @@ void VPWidenIntrinsicRecipe::execute(VPTransformState &State) {
 
   if (!V->getType()->isVoidTy())
     State.set(this, V);
-  State.addMetadata(V, CI);
+  setMetadata(V);
 }
 
 InstructionCost VPWidenIntrinsicRecipe::computeCost(ElementCount VF,
@@ -1465,7 +1473,7 @@ void VPWidenSelectRecipe::execute(VPTransformState &State) {
   State.set(this, Sel);
   if (isa<FPMathOperator>(Sel))
     setFlags(cast<Instruction>(Sel));
-  State.addMetadata(Sel, dyn_cast_or_null<Instruction>(getUnderlyingValue()));
+  setMetadata(Sel);
 }
 
 InstructionCost VPWidenSelectRecipe::computeCost(ElementCount VF,
@@ -1601,7 +1609,7 @@ void VPWidenRecipe::execute(VPTransformState &State) {
 
     // Use this vector value for all users of the original instruction.
     State.set(this, V);
-    State.addMetadata(V, dyn_cast_or_null<Instruction>(getUnderlyingValue()));
+    setMetadata(V);
     break;
   }
   case Instruction::ExtractValue: {
@@ -1634,7 +1642,7 @@ void VPWidenRecipe::execute(VPTransformState &State) {
       C = Builder.CreateICmp(getPredicate(), A, B);
     }
     State.set(this, C);
-    State.addMetadata(C, dyn_cast_or_null<Instruction>(getUnderlyingValue()));
+    setMetadata(C);
     break;
   }
   default:
@@ -1750,9 +1758,10 @@ void VPWidenCastRecipe::execute(VPTransformState &State) {
   Value *A = State.get(Op);
   Value *Cast = Builder.CreateCast(Instruction::CastOps(Opcode), A, DestTy);
   State.set(this, Cast);
-  State.addMetadata(Cast, cast_or_null<Instruction>(getUnderlyingValue()));
-  if (auto *CastOp = dyn_cast<Instruction>(Cast))
+  if (auto *CastOp = dyn_cast<Instruction>(Cast)) {
     setFlags(CastOp);
+    setMetadata(CastOp);
+  }
 }
 
 InstructionCost VPWidenCastRecipe::computeCost(ElementCount VF,
@@ -2735,7 +2744,8 @@ void VPWidenLoadRecipe::execute(VPTransformState &State) {
     NewLI = Builder.CreateAlignedLoad(DataTy, Addr, Alignment, "wide.load");
   }
   // Add metadata to the load, but setVectorValue to the reverse shuffle.
-  State.addMetadata(NewLI, LI);
+  State.addNewMetadata(NewLI, LI);
+  setMetadata(NewLI);
   if (Reverse)
     NewLI = Builder.CreateVectorReverse(NewLI, "reverse");
   State.set(this, NewLI);
@@ -2795,7 +2805,8 @@ void VPWidenLoadEVLRecipe::execute(VPTransformState &State) {
   }
   NewLI->addParamAttr(
       0, Attribute::getWithAlignment(NewLI->getContext(), Alignment));
-  State.addMetadata(NewLI, LI);
+  State.addNewMetadata(NewLI, LI);
+  setMetadata(NewLI);
   Instruction *Res = NewLI;
   if (isReverse())
     Res = createReverseEVL(Builder, Res, EVL, "vp.reverse");
@@ -2871,7 +2882,8 @@ void VPWidenStoreRecipe::execute(VPTransformState &State) {
     NewSI = Builder.CreateMaskedStore(StoredVal, Addr, Alignment, Mask);
   else
     NewSI = Builder.CreateAlignedStore(StoredVal, Addr, Alignment);
-  State.addMetadata(NewSI, SI);
+  State.addNewMetadata(NewSI, SI);
+  setMetadata(NewSI);
 }
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
@@ -2918,7 +2930,8 @@ void VPWidenStoreEVLRecipe::execute(VPTransformState &State) {
   }
   NewSI->addParamAttr(
       1, Attribute::getWithAlignment(NewSI->getContext(), Alignment));
-  State.addMetadata(NewSI, SI);
+  State.addNewMetadata(NewSI, SI);
+  setMetadata(NewSI);
 }
 
 InstructionCost VPWidenStoreEVLRecipe::computeCost(ElementCount VF,

@llvmbot
Copy link
Member

llvmbot commented Apr 10, 2025

@llvm/pr-subscribers-vectorizers

Author: Florian Hahn (fhahn)

Changes

Add a new helper to manage IR metadata that can be progated to generated instructions for recipes.

This helps to remove a number of remaining uses of getUnderlyingInstr during VPlan execution.


Full diff: https://github.com/llvm/llvm-project/pull/135272.diff

4 Files Affected:

  • (modified) llvm/lib/Transforms/Vectorize/VPlan.cpp (+5-15)
  • (modified) llvm/lib/Transforms/Vectorize/VPlan.h (+35-17)
  • (modified) llvm/lib/Transforms/Vectorize/VPlanHelpers.h (+1-8)
  • (modified) llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp (+24-11)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 9474e7a171dff..229949725128a 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -356,23 +356,13 @@ BasicBlock *VPTransformState::CFGState::getPreheaderBBFor(VPRecipeBase *R) {
   return VPBB2IRBB[LoopRegion->getPreheaderVPBB()];
 }
 
-void VPTransformState::addNewMetadata(Instruction *To,
-                                      const Instruction *Orig) {
+void VPTransformState::addNewMetadata(Value *To, const Instruction *Orig) {
+
   // If the loop was versioned with memchecks, add the corresponding no-alias
   // metadata.
-  if (LVer && isa<LoadInst, StoreInst>(Orig))
-    LVer->annotateInstWithNoAlias(To, Orig);
-}
-
-void VPTransformState::addMetadata(Value *To, Instruction *From) {
-  // No source instruction to transfer metadata from?
-  if (!From)
-    return;
-
-  if (Instruction *ToI = dyn_cast<Instruction>(To)) {
-    propagateMetadata(ToI, From);
-    addNewMetadata(ToI, From);
-  }
+  Instruction *ToI = dyn_cast<Instruction>(To);
+  if (ToI && LVer && isa<LoadInst, StoreInst>(Orig))
+    LVer->annotateInstWithNoAlias(ToI, Orig);
 }
 
 void VPTransformState::setDebugLocFrom(DebugLoc DL) {
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 669e8f371d3d3..11f637f7b1518 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1114,18 +1114,33 @@ struct VPIRPhi : public VPIRInstruction {
 #endif
 };
 
+/// Helper to manage IR metadata for recipes. It filters out metadata that
+/// cannot be proagated.
+class VPWithIRMetadata {
+  SmallVector<std::pair<unsigned, MDNode *>> Metadata;
+
+public:
+  VPWithIRMetadata() {}
+
+  VPWithIRMetadata(Instruction &I) { getMetadataToPropagate(&I, Metadata); }
+
+  /// Add all metadata to \p V if it is an instruction.
+  void setMetadata(Value *V) const;
+};
+
 /// VPWidenRecipe is a recipe for producing a widened instruction using the
 /// opcode and operands of the recipe. This recipe covers most of the
 /// traditional vectorization cases where each recipe transforms into a
 /// vectorized version of itself.
-class VPWidenRecipe : public VPRecipeWithIRFlags {
+class VPWidenRecipe : public VPRecipeWithIRFlags, public VPWithIRMetadata {
   unsigned Opcode;
 
 protected:
   template <typename IterT>
   VPWidenRecipe(unsigned VPDefOpcode, Instruction &I,
                 iterator_range<IterT> Operands)
-      : VPRecipeWithIRFlags(VPDefOpcode, Operands, I), Opcode(I.getOpcode()) {}
+      : VPRecipeWithIRFlags(VPDefOpcode, Operands, I), VPWithIRMetadata(I),
+        Opcode(I.getOpcode()) {}
 
 public:
   template <typename IterT>
@@ -1160,7 +1175,7 @@ class VPWidenRecipe : public VPRecipeWithIRFlags {
 };
 
 /// VPWidenCastRecipe is a recipe to create vector cast instructions.
-class VPWidenCastRecipe : public VPRecipeWithIRFlags {
+class VPWidenCastRecipe : public VPRecipeWithIRFlags, public VPWithIRMetadata {
   /// Cast instruction opcode.
   Instruction::CastOps Opcode;
 
@@ -1170,15 +1185,15 @@ class VPWidenCastRecipe : public VPRecipeWithIRFlags {
 public:
   VPWidenCastRecipe(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy,
                     CastInst &UI)
-      : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op, UI), Opcode(Opcode),
-        ResultTy(ResultTy) {
+      : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op, UI), VPWithIRMetadata(UI),
+        Opcode(Opcode), ResultTy(ResultTy) {
     assert(UI.getOpcode() == Opcode &&
            "opcode of underlying cast doesn't match");
   }
 
   VPWidenCastRecipe(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy)
-      : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op), Opcode(Opcode),
-        ResultTy(ResultTy) {}
+      : VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op), VPWithIRMetadata(),
+        Opcode(Opcode), ResultTy(ResultTy) {}
 
   ~VPWidenCastRecipe() override = default;
 
@@ -1260,7 +1275,8 @@ class VPScalarCastRecipe : public VPSingleDefRecipe {
 };
 
 /// A recipe for widening vector intrinsics.
-class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags {
+class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags,
+                               public VPWithIRMetadata {
   /// ID of the vector intrinsic to widen.
   Intrinsic::ID VectorIntrinsicID;
 
@@ -1281,8 +1297,8 @@ class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags {
                          ArrayRef<VPValue *> CallArguments, Type *Ty,
                          DebugLoc DL = {})
       : VPRecipeWithIRFlags(VPDef::VPWidenIntrinsicSC, CallArguments, CI),
-        VectorIntrinsicID(VectorIntrinsicID), ResultTy(Ty),
-        MayReadFromMemory(CI.mayReadFromMemory()),
+        VPWithIRMetadata(CI), VectorIntrinsicID(VectorIntrinsicID),
+        ResultTy(Ty), MayReadFromMemory(CI.mayReadFromMemory()),
         MayWriteToMemory(CI.mayWriteToMemory()),
         MayHaveSideEffects(CI.mayHaveSideEffects()) {}
 
@@ -1346,7 +1362,7 @@ class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags {
 };
 
 /// A recipe for widening Call instructions using library calls.
-class VPWidenCallRecipe : public VPRecipeWithIRFlags {
+class VPWidenCallRecipe : public VPRecipeWithIRFlags, public VPWithIRMetadata {
   /// Variant stores a pointer to the chosen function. There is a 1:1 mapping
   /// between a given VF and the chosen vectorized variant, so there will be a
   /// different VPlan for each VF with a valid variant.
@@ -1357,7 +1373,7 @@ class VPWidenCallRecipe : public VPRecipeWithIRFlags {
                     ArrayRef<VPValue *> CallArguments, DebugLoc DL = {})
       : VPRecipeWithIRFlags(VPDef::VPWidenCallSC, CallArguments,
                             *cast<Instruction>(UV)),
-        Variant(Variant) {
+        VPWithIRMetadata(*cast<Instruction>(UV)), Variant(Variant) {
     assert(
         isa<Function>(getOperand(getNumOperands() - 1)->getLiveInIRValue()) &&
         "last operand must be the called function");
@@ -1443,10 +1459,12 @@ class VPHistogramRecipe : public VPRecipeBase {
 };
 
 /// A recipe for widening select instructions.
-struct VPWidenSelectRecipe : public VPRecipeWithIRFlags {
+struct VPWidenSelectRecipe : public VPRecipeWithIRFlags,
+                             public VPWithIRMetadata {
   template <typename IterT>
   VPWidenSelectRecipe(SelectInst &I, iterator_range<IterT> Operands)
-      : VPRecipeWithIRFlags(VPDef::VPWidenSelectSC, Operands, I) {}
+      : VPRecipeWithIRFlags(VPDef::VPWidenSelectSC, Operands, I),
+        VPWithIRMetadata(I) {}
 
   ~VPWidenSelectRecipe() override = default;
 
@@ -2564,7 +2582,7 @@ class VPPredInstPHIRecipe : public VPSingleDefRecipe {
 
 /// A common base class for widening memory operations. An optional mask can be
 /// provided as the last operand.
-class VPWidenMemoryRecipe : public VPRecipeBase {
+class VPWidenMemoryRecipe : public VPRecipeBase, public VPWithIRMetadata {
 protected:
   Instruction &Ingredient;
 
@@ -2588,8 +2606,8 @@ class VPWidenMemoryRecipe : public VPRecipeBase {
   VPWidenMemoryRecipe(const char unsigned SC, Instruction &I,
                       std::initializer_list<VPValue *> Operands,
                       bool Consecutive, bool Reverse, DebugLoc DL)
-      : VPRecipeBase(SC, Operands, DL), Ingredient(I), Consecutive(Consecutive),
-        Reverse(Reverse) {
+      : VPRecipeBase(SC, Operands, DL), VPWithIRMetadata(I), Ingredient(I),
+        Consecutive(Consecutive), Reverse(Reverse) {
     assert((Consecutive || !Reverse) && "Reverse implies consecutive");
   }
 
diff --git a/llvm/lib/Transforms/Vectorize/VPlanHelpers.h b/llvm/lib/Transforms/Vectorize/VPlanHelpers.h
index bebea1915690f..4826dfd562c2d 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanHelpers.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanHelpers.h
@@ -288,14 +288,7 @@ struct VPTransformState {
   /// Currently this is used to add the noalias annotations based on the
   /// inserted memchecks.  Use this for instructions that are *cloned* into the
   /// vector loop.
-  void addNewMetadata(Instruction *To, const Instruction *Orig);
-
-  /// Add metadata from one instruction to another.
-  ///
-  /// This includes both the original MDs from \p From and additional ones (\see
-  /// addNewMetadata).  Use this for *newly created* instructions in the vector
-  /// loop.
-  void addMetadata(Value *To, Instruction *From);
+  void addNewMetadata(Value *To, const Instruction *Orig);
 
   /// Set the debug location in the builder using the debug location \p DL.
   void setDebugLocFrom(DebugLoc DL);
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 35e141ed01267..077867cbc7a92 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1159,6 +1159,14 @@ void VPIRPhi::print(raw_ostream &O, const Twine &Indent,
 }
 #endif
 
+void VPWithIRMetadata::setMetadata(Value *V) const {
+  auto *I = dyn_cast<Instruction>(V);
+  if (!I)
+    return;
+  for (const auto &[Kind, Node] : Metadata)
+    I->setMetadata(Kind, Node);
+}
+
 void VPWidenCallRecipe::execute(VPTransformState &State) {
   assert(State.VF.isVector() && "not widening");
 
@@ -1189,7 +1197,7 @@ void VPWidenCallRecipe::execute(VPTransformState &State) {
 
   if (!V->getType()->isVoidTy())
     State.set(this, V);
-  State.addMetadata(V, CI);
+  setMetadata(V);
 }
 
 InstructionCost VPWidenCallRecipe::computeCost(ElementCount VF,
@@ -1268,7 +1276,7 @@ void VPWidenIntrinsicRecipe::execute(VPTransformState &State) {
 
   if (!V->getType()->isVoidTy())
     State.set(this, V);
-  State.addMetadata(V, CI);
+  setMetadata(V);
 }
 
 InstructionCost VPWidenIntrinsicRecipe::computeCost(ElementCount VF,
@@ -1465,7 +1473,7 @@ void VPWidenSelectRecipe::execute(VPTransformState &State) {
   State.set(this, Sel);
   if (isa<FPMathOperator>(Sel))
     setFlags(cast<Instruction>(Sel));
-  State.addMetadata(Sel, dyn_cast_or_null<Instruction>(getUnderlyingValue()));
+  setMetadata(Sel);
 }
 
 InstructionCost VPWidenSelectRecipe::computeCost(ElementCount VF,
@@ -1601,7 +1609,7 @@ void VPWidenRecipe::execute(VPTransformState &State) {
 
     // Use this vector value for all users of the original instruction.
     State.set(this, V);
-    State.addMetadata(V, dyn_cast_or_null<Instruction>(getUnderlyingValue()));
+    setMetadata(V);
     break;
   }
   case Instruction::ExtractValue: {
@@ -1634,7 +1642,7 @@ void VPWidenRecipe::execute(VPTransformState &State) {
       C = Builder.CreateICmp(getPredicate(), A, B);
     }
     State.set(this, C);
-    State.addMetadata(C, dyn_cast_or_null<Instruction>(getUnderlyingValue()));
+    setMetadata(C);
     break;
   }
   default:
@@ -1750,9 +1758,10 @@ void VPWidenCastRecipe::execute(VPTransformState &State) {
   Value *A = State.get(Op);
   Value *Cast = Builder.CreateCast(Instruction::CastOps(Opcode), A, DestTy);
   State.set(this, Cast);
-  State.addMetadata(Cast, cast_or_null<Instruction>(getUnderlyingValue()));
-  if (auto *CastOp = dyn_cast<Instruction>(Cast))
+  if (auto *CastOp = dyn_cast<Instruction>(Cast)) {
     setFlags(CastOp);
+    setMetadata(CastOp);
+  }
 }
 
 InstructionCost VPWidenCastRecipe::computeCost(ElementCount VF,
@@ -2735,7 +2744,8 @@ void VPWidenLoadRecipe::execute(VPTransformState &State) {
     NewLI = Builder.CreateAlignedLoad(DataTy, Addr, Alignment, "wide.load");
   }
   // Add metadata to the load, but setVectorValue to the reverse shuffle.
-  State.addMetadata(NewLI, LI);
+  State.addNewMetadata(NewLI, LI);
+  setMetadata(NewLI);
   if (Reverse)
     NewLI = Builder.CreateVectorReverse(NewLI, "reverse");
   State.set(this, NewLI);
@@ -2795,7 +2805,8 @@ void VPWidenLoadEVLRecipe::execute(VPTransformState &State) {
   }
   NewLI->addParamAttr(
       0, Attribute::getWithAlignment(NewLI->getContext(), Alignment));
-  State.addMetadata(NewLI, LI);
+  State.addNewMetadata(NewLI, LI);
+  setMetadata(NewLI);
   Instruction *Res = NewLI;
   if (isReverse())
     Res = createReverseEVL(Builder, Res, EVL, "vp.reverse");
@@ -2871,7 +2882,8 @@ void VPWidenStoreRecipe::execute(VPTransformState &State) {
     NewSI = Builder.CreateMaskedStore(StoredVal, Addr, Alignment, Mask);
   else
     NewSI = Builder.CreateAlignedStore(StoredVal, Addr, Alignment);
-  State.addMetadata(NewSI, SI);
+  State.addNewMetadata(NewSI, SI);
+  setMetadata(NewSI);
 }
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
@@ -2918,7 +2930,8 @@ void VPWidenStoreEVLRecipe::execute(VPTransformState &State) {
   }
   NewSI->addParamAttr(
       1, Attribute::getWithAlignment(NewSI->getContext(), Alignment));
-  State.addMetadata(NewSI, SI);
+  State.addNewMetadata(NewSI, SI);
+  setMetadata(NewSI);
 }
 
 InstructionCost VPWidenStoreEVLRecipe::computeCost(ElementCount VF,

@fhahn fhahn force-pushed the vplan-irmetadata branch 3 times, most recently from c45aa04 to b57fc68 Compare April 17, 2025 13:27
SmallVector<std::pair<unsigned, MDNode *>>
VPRecipeBuilder::getMetadataToPropagate(Instruction *I) {
SmallVector<std::pair<unsigned, MDNode *>> Metadata;
::getMetadataToPropagate(I, Metadata);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does ::getMetadataToPropagate() refer to?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a helper to get the metadata that can and should be propagated to the vector instructions: https://github.com/llvm/llvm-project/blob/main/llvm/lib/Analysis/VectorUtils.cpp#L991

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks.
Should these two getMetadataToPropagate() variants be located next to each other, presumably both in VectorUtils?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will need a custom version that also adds no-alias metadata from LoopVersioning (in #136450), which is why i kept it here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should that LVer version also be placed in VectorUtils?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, it is an implementation detail on LV and we would have to pass around the pointer in multiple places.

(It's gone for now in the latest version)

}
Instruction *ToI = dyn_cast<Instruction>(To);
if (ToI && LVer && isa<LoadInst, StoreInst>(Orig))
LVer->annotateInstWithNoAlias(ToI, Orig);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better add the corresponding no-alias metadata to VPWithIRMetadata of relevant recipe, than to the ToI it generates during execution?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, this is probably best done separately as follow-up: #136450


/// Helper to manage IR metadata for recipes. It filters out metadata that
/// cannot be proagated.
class VPWithIRMetadata {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"With" seems redundant here. There are IRFlags and IRMetadata, there are recipes With the former or the latter or both or none. IRFlags are modeled by relevant VPlan recipes using a nameless union which VPRecipeWithIRFlags "has", rather than inherits from. VP[IR]FlagsTy might be an appropriate name for this union, and VP[IR]Flags a name for a base class. VP[IR]Metadata may be a consistent name for a base class wrapping IRMetadata.

VPRecipeWithMetadata may serve as a common base class for recipes having metadata but not flags, but according to this patch these currently include only VPWidenMemoryRecipe's, so perhaps currently redundant.

VPRecipeWithFlagsAndMetadata may serve as a common base class for recipes having both, which according to this patch currently include { VPWidenRecipe, VPWidenCallRecipe, VPWidenIntrinsicRecipe, VPWidenCastRecipe and VPWidenSelectRecipe }.

VPRecipeWith[IR]Flags will then continue to serve the following subclasses of recipes having flags but no metadata: { VPInstruction(?), VPReplicateRecipe(?), VPWidenGEPRecipe, VPScalarIVStepsRecipe, VPVectorPointerRecipe, VPReverseVectorPointerRecipe, }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think VPRecipeWithIRFlags is not ideal at the moment, as it makes it more difficult to compose, ideally I think we would move towards replacing it with just VPIRFlags, which the relevant recipes opt in to separately, like VPIRMetadata.

Updated the name as suggested, thanks!

auto *Copy = new VPWidenLoadRecipe(cast<LoadInst>(Ingredient), getAddr(),
getMask(), Consecutive, Reverse,
getMetadata(), getDebugLoc());
Copy->addMetadata(getMetadata());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy already got the metadata upon construction?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep this was left over from an earlier version, removed, thanks!

VPValue(this, &getIngredient()) {
setMask(Mask);
addMetadata(L.getMetadata());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L's metadata was already gotten upon construction?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep this was left over from an earlier version, removed, thanks!

@@ -1204,6 +1204,14 @@ void VPIRPhi::print(raw_ostream &O, const Twine &Indent,
}
#endif

void VPWithIRMetadata::setMetadata(Value *V) const {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better have the caller dyn_cast to Instruction (and realize metadata may be lost for non Instruction Values) than pretend this can set metadata to any Value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could do if preferred, but then we would need to update every caller?

Comment on lines 1242 to 1245

if (!V->getType()->isVoidTy())
State.set(this, V);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: good to place setMetadata() next to setFlags() in general, here and below.

Suggested change
if (!V->getType()->isVoidTy())
State.set(this, V);
setMetadata(V);
if (!V->getType()->isVoidTy())
State.set(this, V);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done thanks

@@ -1234,7 +1242,7 @@ void VPWidenCallRecipe::execute(VPTransformState &State) {

if (!V->getType()->isVoidTy())
State.set(this, V);
State.addMetadata(V, CI);
setMetadata(V);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: good to place setMetadata() next to setFlags() in general, here and below.

Suggested change
setMetadata(V);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done thanks

@@ -1646,7 +1654,7 @@ void VPWidenRecipe::execute(VPTransformState &State) {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here setFlags() is already applied under dyn_cast to Instruction. Place setMetadata() here as well, or rather applyMetadata(Instruction*)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thanks

@@ -69,20 +69,22 @@ bool VPlanTransforms::tryToConvertVPInstructionsToVPRecipes(
NewRecipe = new VPWidenIntOrFpInductionRecipe(
Phi, Start, Step, &Plan->getVF(), *II, Ingredient.getDebugLoc());
} else {
SmallVector<std::pair<unsigned, MDNode *>> Metadata;
getMetadataToPropagate(Inst, Metadata);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recipe constructors above called getMetadataToPropagate(underlying Instruction) inline. Here we want to record Metadata earlier for several alternative users. Would doing Metadata = getMetadataToPropagate(Inst) work and be more consistent? Alternatively, could the metadata be added to NewRecipe after its construction?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated to use VPRecipeBuilder::getMetadataToPropagate, thanks

fhahn added 2 commits April 19, 2025 20:13
Add a new helper to manage IR metadata that can be progated to generated
instructions for recipes.

This helps to remove a number of remaining uses of getUnderlyingInstr
during VPlan execution.

Add metadata on cloning.
@fhahn fhahn force-pushed the vplan-irmetadata branch from b57fc68 to d3edd89 Compare April 19, 2025 19:16
fhahn added a commit to fhahn/llvm-project that referenced this pull request Apr 19, 2025
Use VPIRMetadata added in llvm#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.
@@ -8599,11 +8599,13 @@ VPRecipeBuilder::tryToWidenMemory(Instruction *I, ArrayRef<VPValue *> Operands,
}
if (LoadInst *Load = dyn_cast<LoadInst>(I))
return new VPWidenLoadRecipe(*Load, Ptr, Mask, Consecutive, Reverse,
getMetadataToPropagate(Load),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If passing the metadata relieves the need to pass and store the underlying insn - great!
If the underlying insn is still needed, would it be better to have the constructor extract its metadata (to propagate, thereby reducing the diff), rather than pass both parameters independently, or are there cases where some other metadata is desired - e.g. none, as appears below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, although it will need explicit passing in #136450

SmallVector<std::pair<unsigned, MDNode *>>
VPRecipeBuilder::getMetadataToPropagate(Instruction *I) {
SmallVector<std::pair<unsigned, MDNode *>> Metadata;
::getMetadataToPropagate(I, Metadata);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks.
Should these two getMetadataToPropagate() variants be located next to each other, presumably both in VectorUtils?

assert(UI.getOpcode() == Opcode &&
"opcode of underlying cast doesn't match");
}

VPWidenCastRecipe(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy)
: VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op), Opcode(Opcode),
ResultTy(ResultTy) {}
: VPRecipeWithIRFlags(VPDef::VPWidenCastSC, Op), VPIRMetadata({}),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constructor has neither an underlying instruction nor any metadata.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep to keep NFC, also removed the metadata arg from VPWidenIntrinsicRecipe. Can be added in follow-ups to retain additional metadata.

MayWriteToMemory(CI.mayWriteToMemory()),
MayHaveSideEffects(CI.mayHaveSideEffects()) {}

VPWidenIntrinsicRecipe(Intrinsic::ID VectorIntrinsicID,
ArrayRef<VPValue *> CallArguments, Type *Ty,
DebugLoc DL = {})
MDArrayRef Metadata, DebugLoc DL = {})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constructor has no underlying instruction but does accept metadata.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed for now to keep this NFC. There are cases where we convert VPWidenIntrinsic recipes from wide recieps that can have metadata, which could be retained now. But best for a future change + test

setFlags(VecOp);
applyMetadata(V);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
applyMetadata(V);
applyMetadata(VecOp);

(consistency)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done thanks

Comment on lines 2016 to 2017
Intrinsic::vp_select, Ops, TypeInfo.inferScalarType(Sel),
Sel->getMetadata(), Sel->getDebugLoc());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and below VPWidenIntrinsicRecipe is relieved from receiving the underlying instruction Sel, so its metadata needs to be passed.

@@ -2755,7 +2758,7 @@ void VPlanTransforms::narrowInterleaveGroups(VPlan &Plan, ElementCount VF,
auto *L = new VPWidenLoadRecipe(
*cast<LoadInst>(LoadGroup->getInterleaveGroup()->getInsertPos()),
LoadGroup->getAddr(), LoadGroup->getMask(), /*Consecutive=*/true,
/*Reverse=*/false, LoadGroup->getDebugLoc());
/*Reverse=*/false, {}, LoadGroup->getDebugLoc());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The single widenLoad/StoreRecipe in this case drops the metadata of its insertPos/underlying load/store? Seems an exception worthy of a note, perhaps an explicit subsequent dropMetadata() call?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is no longer needed?

@@ -929,7 +929,7 @@ TEST_F(VPRecipeTest, CastVPWidenRecipeToVPUser) {
SmallVector<VPValue *, 2> Args;
Args.push_back(Op1);
Args.push_back(Op2);
VPWidenRecipe WidenR(*AI, make_range(Args.begin(), Args.end()));
VPWidenRecipe WidenR(*AI, make_range(Args.begin(), Args.end()), {});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and below newly created Instructions are wrapped in widen recipes, should their metadata be preserved (by default) rather than dropped (explicitly)?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just for testing casting recipes, so I don't think the metadata matters here

Comment on lines 1204 to 1205
/// Add all metadata to \p V if it is an instruction.
void applyMetadata(Value *V) const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(original post outdated as it referred to setMetadata(), resurrecting here)

Better have the caller dyn_cast to Instruction (and realize metadata may be lost for non Instruction Values) than pretend this can set metadata to any Value?

Could do if preferred, but then we would need to update every caller?

Yes, admittedly, consistent with setFlags().
In some cases an assert/cast may be appropriate rather than a dyn_cast, when value is expected to be an instruction (otherwise cost may be inaccurate?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turns out most places already check for instructions or have instructions. Updated to always pass as instruction, thanks!

setFlags already only accepts an instruction

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, suggestion was inspired by setFlags(Instruction*).

fhahn added a commit that referenced this pull request Apr 21, 2025
Update name to apply flags to instructions, as suggested in
#135272.

Also changes the arg to a reference.
Copy link
Collaborator

@ayalz ayalz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments relate to outdated changes.

Comment on lines 2721 to 2724
auto *Copy =
new VPWidenLoadRecipe(cast<LoadInst>(Ingredient), getAddr(), getMask(),
Consecutive, Reverse, getDebugLoc());
return Copy;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retain existing inlined version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, thanks

Comment on lines 2799 to 2802
auto *Copy = new VPWidenStoreRecipe(cast<StoreInst>(Ingredient), getAddr(),
getStoredValue(), getMask(),
Consecutive, Reverse, getDebugLoc());
return Copy;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, thanks

@@ -2626,8 +2652,8 @@ class VPWidenMemoryRecipe : public VPRecipeBase {
VPWidenMemoryRecipe(const char unsigned SC, Instruction &I,
std::initializer_list<VPValue *> Operands,
bool Consecutive, bool Reverse, DebugLoc DL)
: VPRecipeBase(SC, Operands, DL), Ingredient(I), Consecutive(Consecutive),
Reverse(Reverse) {
: VPRecipeBase(SC, Operands, DL), VPIRMetadata(I), Ingredient(I),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this way of initializing VPIRMetadata(I) be applied to all recipe constructors that receive their underlying instruction I as parameter? This seems like a natural default behavior, could be followed by an update if some other exceptional metadata is desired.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated for now, although it might be good to encourage avoidance of relying on underlying instructions on construction ;)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Certainly, by all means!
Any recipe that can be constructed w/o an underlying instruction should be; at that point its metadata can be passed instead of the instruction itself.

SmallVector<std::pair<unsigned, MDNode *>>
VPRecipeBuilder::getMetadataToPropagate(Instruction *I) {
SmallVector<std::pair<unsigned, MDNode *>> Metadata;
::getMetadataToPropagate(I, Metadata);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should that LVer version also be placed in VectorUtils?

@@ -929,7 +929,7 @@ TEST_F(VPRecipeTest, CastVPWidenRecipeToVPUser) {
SmallVector<VPValue *, 2> Args;
Args.push_back(Op1);
Args.push_back(Op2);
VPWidenRecipe WidenR(*AI, make_range(Args.begin(), Args.end()));
VPWidenRecipe WidenR(*AI, make_range(Args.begin(), Args.end()), {});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?


public:
/// Add all metadata to \p V if it is an instruction.
void setMetadata(Value *V) const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pushing applyFlags() separately!

Comment on lines 1204 to 1205
/// Add all metadata to \p V if it is an instruction.
void applyMetadata(Value *V) const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, suggestion was inspired by setFlags(Instruction*).

@@ -2755,7 +2758,7 @@ void VPlanTransforms::narrowInterleaveGroups(VPlan &Plan, ElementCount VF,
auto *L = new VPWidenLoadRecipe(
*cast<LoadInst>(LoadGroup->getInterleaveGroup()->getInsertPos()),
LoadGroup->getAddr(), LoadGroup->getMask(), /*Consecutive=*/true,
/*Reverse=*/false, LoadGroup->getDebugLoc());
/*Reverse=*/false, {}, LoadGroup->getDebugLoc());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is no longer needed?

@david-arm
Copy link
Contributor

Hi @fhahn, should the title of the ticket be "[VPlan] Manage instruction metadata in VPlan."?

Comment on lines 358 to 359
void VPTransformState::addNewMetadata(Value *To, const Instruction *Orig) {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change still needed, now that metadata is applied to Instructions rather than Values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored thanks

@@ -1190,18 +1190,33 @@ struct VPIRPhi : public VPIRInstruction {
#endif
};

/// Helper to manage IR metadata for recipes. It filters out metadata that
/// cannot be proagated.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// cannot be proagated.
/// cannot be propagated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed thanks

@@ -2626,8 +2652,8 @@ class VPWidenMemoryRecipe : public VPRecipeBase {
VPWidenMemoryRecipe(const char unsigned SC, Instruction &I,
std::initializer_list<VPValue *> Operands,
bool Consecutive, bool Reverse, DebugLoc DL)
: VPRecipeBase(SC, Operands, DL), Ingredient(I), Consecutive(Consecutive),
Reverse(Reverse) {
: VPRecipeBase(SC, Operands, DL), VPIRMetadata(I), Ingredient(I),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Certainly, by all means!
Any recipe that can be constructed w/o an underlying instruction should be; at that point its metadata can be passed instead of the instruction itself.

Comment on lines +1517 to +1521
if (auto *I = dyn_cast<Instruction>(Sel)) {
if (isa<FPMathOperator>(I))
applyFlags(*I);
applyMetadata(*I);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent, consistency nit: good to keep State.set() as the last operation of execute(), after fully finishing to build the new instruction/value, including applying its flags/metadata. Conceptually, flags and metadata could be folded into Builder.CreateSelect().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can do separately, thanks.

Comment on lines -1800 to +1811
if (auto *CastOp = dyn_cast<Instruction>(Cast))
if (auto *CastOp = dyn_cast<Instruction>(Cast)) {
applyFlags(*CastOp);
applyMetadata(*CastOp);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same independent consistency nit.

Comment on lines 2767 to 2768
State.set(this,
Reverse ? Builder.CreateVectorReverse(NewLI, "reverse") : NewLI);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is to avoid casting the vector reverse of NewLI to Instruction:

  if (Reverse)
    NewLI = cast<Instruction>(Builder.CreateVectorReverse(NewLI, "reverse"));
  State.set(this, NewLI);

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, otherwise we need to cast, could also change if desired

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, keeping State.set() separate as the last operation after completing the creation of instructions would be more consistent, e.g., also with VPWidenLoadEVLRecipe::execute() below. BTW, better ask here if (isReverse()) as asked there and above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

restored thanks

@@ -950,7 +950,7 @@ TEST_F(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPDef) {
Args.push_back(Op1);
Args.push_back(Op2);
Args.push_back(CalledFn);
VPWidenCallRecipe Recipe(Call, Fn, Args);
VPWidenCallRecipe Recipe(Call, Fn, Args, {});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change needed, here and below, given that the last DL argument defaults to {}?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed, thanks

@fhahn fhahn changed the title [VPlan] Manage instruction medata in VPlan. [VPlan] Manage instruction metadata in VPlan. Apr 22, 2025
Copy link
Contributor Author

@fhahn fhahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @fhahn, should the title of the ticket be "[VPlan] Manage instruction metadata in VPlan."?

Yep, the typo should be fixed thanks!

Comment on lines 358 to 359
void VPTransformState::addNewMetadata(Value *To, const Instruction *Orig) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored thanks

@@ -1190,18 +1190,33 @@ struct VPIRPhi : public VPIRInstruction {
#endif
};

/// Helper to manage IR metadata for recipes. It filters out metadata that
/// cannot be proagated.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed thanks

Comment on lines +1517 to +1521
if (auto *I = dyn_cast<Instruction>(Sel)) {
if (isa<FPMathOperator>(I))
applyFlags(*I);
applyMetadata(*I);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can do separately, thanks.

Comment on lines 2767 to 2768
State.set(this,
Reverse ? Builder.CreateVectorReverse(NewLI, "reverse") : NewLI);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, otherwise we need to cast, could also change if desired

@@ -950,7 +950,7 @@ TEST_F(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPDef) {
Args.push_back(Op1);
Args.push_back(Op2);
Args.push_back(CalledFn);
VPWidenCallRecipe Recipe(Call, Fn, Args);
VPWidenCallRecipe Recipe(Call, Fn, Args, {});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed, thanks

Copy link
Collaborator

@ayalz ayalz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks! Adding few minor comments.

@@ -1257,7 +1257,7 @@ TEST_F(VPRecipeTest, MayHaveSideEffectsAndMayReadWriteMemory) {
Args.push_back(Op1);
Args.push_back(Op2);
Args.push_back(CalledFn);
VPWidenCallRecipe Recipe(Call, TheFn, Args);
VPWidenCallRecipe Recipe(Call, TheFn, Args, {});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes removed, thanks

Comment on lines 2767 to 2768
State.set(this,
Reverse ? Builder.CreateVectorReverse(NewLI, "reverse") : NewLI);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, keeping State.set() separate as the last operation after completing the creation of instructions would be more consistent, e.g., also with VPWidenLoadEVLRecipe::execute() below. BTW, better ask here if (isReverse()) as asked there and above.

@@ -290,13 +290,6 @@ struct VPTransformState {
/// vector loop.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the above description still accurate? Would be good to clarify when State.addNewMetadata(To, Orig) needs to complement applyMetadata(To). Will possibly be handled by #136450

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is still accurate; applyMetadata in this patch applies metadata already on Orig, while addNewMetadata adds metadata from versioning, not present at the original instructions.

@fhahn fhahn merged commit 5d136f9 into llvm:main Apr 24, 2025
11 checks passed
@fhahn fhahn deleted the vplan-irmetadata branch April 24, 2025 10:58
fhahn added a commit to fhahn/llvm-project that referenced this pull request Apr 24, 2025
Use VPIRMetadata added in llvm#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.
fhahn added a commit to fhahn/llvm-project that referenced this pull request Apr 28, 2025
Use VPIRMetadata added in llvm#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.
fhahn added a commit to fhahn/llvm-project that referenced this pull request Apr 29, 2025
Use VPIRMetadata added in llvm#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.
fhahn added a commit to fhahn/llvm-project that referenced this pull request May 3, 2025
Use VPIRMetadata added in llvm#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.
fhahn added a commit to fhahn/llvm-project that referenced this pull request May 4, 2025
Use VPIRMetadata added in llvm#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.
fhahn added a commit to fhahn/llvm-project that referenced this pull request May 4, 2025
Use VPIRMetadata added in llvm#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.

!fixup move applyMetadata;

!fixup address comments, thanks

!fixup address remaining comments, thanks

!fixup address latest comments, thanks
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 6, 2025
Update name to apply flags to instructions, as suggested in
llvm/llvm-project#135272.

Also changes the arg to a reference.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 6, 2025
Add a new helper to manage IR metadata that can be progated to generated
instructions for recipes.

This helps to remove a number of remaining uses of getUnderlyingInstr
during VPlan execution.

PR: llvm/llvm-project#135272
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
Update name to apply flags to instructions, as suggested in
llvm#135272.

Also changes the arg to a reference.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
Add a new helper to manage IR metadata that can be progated to generated
instructions for recipes.

This helps to remove a number of remaining uses of getUnderlyingInstr
during VPlan execution.

PR: llvm#135272
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
Update name to apply flags to instructions, as suggested in
llvm#135272.

Also changes the arg to a reference.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
Add a new helper to manage IR metadata that can be progated to generated
instructions for recipes.

This helps to remove a number of remaining uses of getUnderlyingInstr
during VPlan execution.

PR: llvm#135272
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
Update name to apply flags to instructions, as suggested in
llvm#135272.

Also changes the arg to a reference.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
Add a new helper to manage IR metadata that can be progated to generated
instructions for recipes.

This helps to remove a number of remaining uses of getUnderlyingInstr
during VPlan execution.

PR: llvm#135272
fhahn added a commit to fhahn/llvm-project that referenced this pull request May 7, 2025
Use VPIRMetadata added in llvm#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.

!fixup move applyMetadata;

!fixup address comments, thanks

!fixup address remaining comments, thanks

!fixup address latest comments, thanks
fhahn added a commit to fhahn/llvm-project that referenced this pull request May 8, 2025
Use VPIRMetadata added in llvm#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.

!fixup move applyMetadata;

!fixup address comments, thanks

!fixup address remaining comments, thanks

!fixup address latest comments, thanks
Ankur-0429 pushed a commit to Ankur-0429/llvm-project that referenced this pull request May 9, 2025
Add a new helper to manage IR metadata that can be progated to generated
instructions for recipes.

This helps to remove a number of remaining uses of getUnderlyingInstr
during VPlan execution.

PR: llvm#135272
fhahn added a commit to fhahn/llvm-project that referenced this pull request May 9, 2025
Use VPIRMetadata added in llvm#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.

!fixup move applyMetadata;

!fixup address comments, thanks

!fixup address remaining comments, thanks

!fixup address latest comments, thanks
fhahn added a commit that referenced this pull request May 9, 2025
Use VPIRMetadata added in
#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.

This also fixes a case where incorrect metadata was added to wide
loads/stores that got converted from an interleave group.

Compile-time impact is neutral:

https://llvm-compile-time-tracker.com/compare.php?from=38bf1af41c5425a552a53feb13c71d82873f1c18&to=2fd7844cfdf5ec0f1c2ce0b9b3ae0763245b6922&stat=instructions:u
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 9, 2025
…6450)

Use VPIRMetadata added in
llvm/llvm-project#135272
to also manage no-alias metadata added by versioning.

Note that this means we have to build the no-alias metadata up-front
once. If it is not used, it will be discarded automatically.

This also fixes a case where incorrect metadata was added to wide
loads/stores that got converted from an interleave group.

Compile-time impact is neutral:

https://llvm-compile-time-tracker.com/compare.php?from=38bf1af41c5425a552a53feb13c71d82873f1c18&to=2fd7844cfdf5ec0f1c2ce0b9b3ae0763245b6922&stat=instructions:u
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants