Skip to content

Conversation

@fhahn
Copy link
Contributor

@fhahn fhahn commented Nov 17, 2025

mplement printing for VPIRMetadata, using generic dyn_cast to VPIRMetadata.

Depends on #166245 (included in the PR)

@llvmbot
Copy link
Member

llvmbot commented Nov 17, 2025

@llvm/pr-subscribers-vectorizers

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

Changes

mplement printing for VPIRMetadata, using generic dyn_cast to VPIRMetadata.

Depends on #166245 (included in the PR)


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

5 Files Affected:

  • (modified) llvm/lib/Transforms/Vectorize/VPlan.h (+81)
  • (modified) llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp (+24)
  • (modified) llvm/test/Transforms/LoopVectorize/vplan-printing-metadata.ll (+9-9)
  • (modified) llvm/unittests/Transforms/Vectorize/VPlanTest.cpp (+31-26)
  • (modified) llvm/unittests/Transforms/Vectorize/VPlanTestBase.h (+10-3)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 13131a2b61722..e1fbce731c31c 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -983,6 +983,11 @@ class VPIRMetadata {
   /// Intersect this VPIRMetada object with \p MD, keeping only metadata
   /// nodes that are common to both.
   void intersect(const VPIRMetadata &MD);
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  /// Print metadata with node IDs.
+  void print(raw_ostream &O, const Module &M) const;
+#endif
 };
 
 /// This is a concrete Recipe that models a single VPlan-level instruction.
@@ -3869,6 +3874,77 @@ template <>
 struct CastInfo<VPPhiAccessors, const VPRecipeBase *>
     : CastInfoVPPhiAccessors<const VPRecipeBase *> {};
 
+/// Casting from VPRecipeBase -> VPIRMetadata is supported for all recipe types
+/// implementing VPIRMetadata. Used by isa<> & co.
+namespace detail {
+/// Returns const VPIRMetadata* if input is const, and VPIRMetadata* otherwise.
+template <typename RecipeBasePtrTy>
+static inline auto castToVPIRMetadata(RecipeBasePtrTy R) -> std::conditional_t<
+    std::is_const_v<std::remove_pointer_t<RecipeBasePtrTy>>,
+    const VPIRMetadata *, VPIRMetadata *> {
+  switch (R->getVPDefID()) {
+  case VPDef::VPInstructionSC:
+    return cast<VPInstruction>(R);
+  case VPDef::VPWidenSC:
+    return cast<VPWidenRecipe>(R);
+  case VPDef::VPWidenCastSC:
+    return cast<VPWidenCastRecipe>(R);
+  case VPDef::VPWidenIntrinsicSC:
+    return cast<VPWidenIntrinsicRecipe>(R);
+  case VPDef::VPWidenCallSC:
+    return cast<VPWidenCallRecipe>(R);
+  case VPDef::VPWidenSelectSC:
+    return cast<VPWidenSelectRecipe>(R);
+  case VPDef::VPReplicateSC:
+    return cast<VPReplicateRecipe>(R);
+  case VPDef::VPInterleaveSC:
+    return cast<VPInterleaveRecipe>(R);
+  case VPDef::VPInterleaveEVLSC:
+    return cast<VPInterleaveEVLRecipe>(R);
+  case VPDef::VPWidenLoadSC:
+    return cast<VPWidenLoadRecipe>(R);
+  case VPDef::VPWidenLoadEVLSC:
+    return cast<VPWidenLoadEVLRecipe>(R);
+  case VPDef::VPWidenStoreSC:
+    return cast<VPWidenStoreRecipe>(R);
+  case VPDef::VPWidenStoreEVLSC:
+    return cast<VPWidenStoreEVLRecipe>(R);
+  default:
+    llvm_unreachable("invalid recipe for VPIRMetadata cast");
+  }
+}
+} // namespace detail
+
+/// Support casting from VPRecipeBase -> VPIRMetadata, by down-casting to the
+/// recipe types implementing VPIRMetadata. Used by cast<>, dyn_cast<> & co.
+template <typename SrcTy>
+struct CastInfoVPIRMetadata : public CastIsPossible<VPIRMetadata, SrcTy> {
+  static inline bool isPossible(SrcTy R) {
+    return isa<VPInstruction, VPWidenRecipe, VPWidenCastRecipe,
+               VPWidenIntrinsicRecipe, VPWidenCallRecipe, VPWidenSelectRecipe,
+               VPReplicateRecipe, VPInterleaveRecipe, VPInterleaveEVLRecipe,
+               VPWidenLoadRecipe, VPWidenLoadEVLRecipe, VPWidenStoreRecipe,
+               VPWidenStoreEVLRecipe>(R);
+  }
+
+  using Self = CastInfo<VPIRMetadata, SrcTy>;
+  using RetTy = decltype(detail::castToVPIRMetadata(std::declval<SrcTy>()));
+
+  static inline RetTy doCast(SrcTy R) { return detail::castToVPIRMetadata(R); }
+
+  static inline RetTy doCastIfPossible(SrcTy R) {
+    if (!Self::isPossible(R))
+      return nullptr;
+    return doCast(R);
+  }
+};
+template <>
+struct CastInfo<VPIRMetadata, VPRecipeBase *>
+    : CastInfoVPIRMetadata<VPRecipeBase *> {};
+template <>
+struct CastInfo<VPIRMetadata, const VPRecipeBase *>
+    : CastInfoVPIRMetadata<const VPRecipeBase *> {};
+
 /// VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph. It
 /// holds a sequence of zero or more VPRecipe's each representing a sequence of
 /// output IR instructions. All PHI-like recipes must come before any non-PHI recipes.
@@ -4333,6 +4409,11 @@ class VPlan {
   /// Return the VPIRBasicBlock wrapping the header of the scalar loop.
   VPIRBasicBlock *getScalarHeader() const { return ScalarHeader; }
 
+  /// Return the Module from the scalar header.
+  const Module &getModule() const {
+    return *ScalarHeader->getIRBasicBlock()->getModule();
+  }
+
   /// Return an ArrayRef containing VPIRBasicBlocks wrapping the exit blocks of
   /// the original scalar loop.
   ArrayRef<VPIRBasicBlock *> getExitBlocks() const { return ExitBlocks; }
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index cf95b4eac9d75..246292b9d9d61 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -489,6 +489,9 @@ void VPSingleDefRecipe::dump() const { VPDef::dump(); }
 void VPRecipeBase::print(raw_ostream &O, const Twine &Indent,
                          VPSlotTracker &SlotTracker) const {
   printRecipe(O, Indent, SlotTracker);
+
+  if (auto *Metadata = dyn_cast<VPIRMetadata>(this))
+    Metadata->print(O, getParent()->getPlan()->getModule());
 }
 #endif
 
@@ -1703,6 +1706,27 @@ void VPIRMetadata::intersect(const VPIRMetadata &Other) {
   Metadata = std::move(MetadataIntersection);
 }
 
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+void VPIRMetadata::print(raw_ostream &O, const Module &M) const {
+  if (Metadata.empty())
+    return;
+
+  SmallVector<StringRef, 8> MDNames;
+  M.getContext().getMDKindNames(MDNames);
+
+  O << " (";
+  interleaveComma(Metadata, O, [&](const auto &KindNodePair) {
+    auto [Kind, Node] = KindNodePair;
+    assert(Kind != 0 && "Debug metadata should not be managed by VPIRMetadata");
+    assert(Kind < MDNames.size() && !MDNames[Kind].empty() &&
+           "Unexpected unnamed metadata kind");
+    O << "!" << MDNames[Kind] << " ";
+    Node->printAsOperand(O, &M);
+  });
+  O << ")";
+}
+#endif
+
 void VPWidenCallRecipe::execute(VPTransformState &State) {
   assert(State.VF.isVector() && "not widening");
   assert(Variant != nullptr && "Can't create vector function.");
diff --git a/llvm/test/Transforms/LoopVectorize/vplan-printing-metadata.ll b/llvm/test/Transforms/LoopVectorize/vplan-printing-metadata.ll
index 857b9131a0b8c..fb49e94ee67bc 100644
--- a/llvm/test/Transforms/LoopVectorize/vplan-printing-metadata.ll
+++ b/llvm/test/Transforms/LoopVectorize/vplan-printing-metadata.ll
@@ -7,11 +7,11 @@ define void @test_widen_metadata(ptr noalias %A, ptr noalias %B, i32 %n) {
 ; CHECK:      VPlan 'Initial VPlan for VF={4},UF>=1' {
 ; CHECK:      <x1> vector loop: {
 ; CHECK:        vector.body:
-; CHECK:          WIDEN ir<%lv> = load vp<{{.*}}>
-; CHECK:          WIDEN-CAST ir<%conv> = sitofp ir<%lv> to float
-; CHECK:          WIDEN ir<%mul> = fmul ir<%conv>, ir<2.000000e+00>
+; CHECK:          WIDEN ir<%lv> = load vp<{{.*}}> (!tbaa !{{[0-9]+}})
+; CHECK:          WIDEN-CAST ir<%conv> = sitofp ir<%lv> to float (!fpmath !{{[0-9]+}})
+; CHECK:          WIDEN ir<%mul> = fmul ir<%conv>, ir<2.000000e+00> (!fpmath !{{[0-9]+}})
 ; CHECK:          WIDEN-CAST ir<%conv.back> = fptosi ir<%mul> to i32
-; CHECK:          WIDEN store vp<{{.*}}>, ir<%conv.back>
+; CHECK:          WIDEN store vp<{{.*}}>, ir<%conv.back> (!tbaa !{{[0-9]+}})
 ;
 entry:
   br label %loop
@@ -40,9 +40,9 @@ define void @test_intrinsic_with_metadata(ptr noalias %A, ptr noalias %B, i32 %n
 ; CHECK:      VPlan 'Initial VPlan for VF={4},UF>=1' {
 ; CHECK:      <x1> vector loop: {
 ; CHECK:        vector.body:
-; CHECK:          WIDEN ir<%lv> = load vp<{{.*}}>
-; CHECK:          WIDEN-INTRINSIC ir<%sqrt> = call llvm.sqrt(ir<%lv>)
-; CHECK:          WIDEN store vp<{{.*}}>, ir<%sqrt>
+; CHECK:          WIDEN ir<%lv> = load vp<{{.*}}> (!tbaa !{{[0-9]+}})
+; CHECK:          WIDEN-INTRINSIC ir<%sqrt> = call llvm.sqrt(ir<%lv>) (!fpmath !{{[0-9]+}})
+; CHECK:          WIDEN store vp<{{.*}}>, ir<%sqrt> (!tbaa !{{[0-9]+}})
 ;
 entry:
   br label %loop
@@ -67,11 +67,11 @@ define void @test_widen_with_multiple_metadata(ptr noalias %A, ptr noalias %B, i
 ; CHECK:      VPlan 'Initial VPlan for VF={4},UF>=1' {
 ; CHECK:      <x1> vector loop: {
 ; CHECK:        vector.body:
-; CHECK:          WIDEN ir<%lv> = load vp<{{.*}}>
+; CHECK:          WIDEN ir<%lv> = load vp<{{.*}}> (!tbaa !{{[0-9]+}})
 ; CHECK:          WIDEN-CAST ir<%conv> = sitofp ir<%lv> to float
 ; CHECK:          WIDEN ir<%mul> = fmul ir<%conv>, ir<2.000000e+00>
 ; CHECK:          WIDEN-CAST ir<%conv.back> = fptosi ir<%mul> to i32
-; CHECK:          WIDEN store vp<{{.*}}>, ir<%conv.back>
+; CHECK:          WIDEN store vp<{{.*}}>, ir<%conv.back> (!tbaa !{{[0-9]+}})
 ;
 entry:
   br label %loop
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
index ee7fa175ca918..7cea64625fe5f 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
@@ -743,8 +743,10 @@ TEST_F(VPBasicBlockTest, print) {
   VPBB2->setName("bb2");
 
   VPBlockUtils::connectBlocks(VPBB1, VPBB2);
+  VPBlockUtils::connectBlocks(VPBB2, Plan.getScalarHeader());
+  VPBlockUtils::connectBlocks(VPBB0, VPBB1);
 
-  // Check printing an instruction without associated VPlan.
+  // Check printing an instruction with associated VPlan.
   {
     std::string I3Dump;
     raw_string_ostream OS(I3Dump);
@@ -753,8 +755,6 @@ TEST_F(VPBasicBlockTest, print) {
     EXPECT_EQ("EMIT store <badref>, <badref>", I3Dump);
   }
 
-  VPBlockUtils::connectBlocks(VPBB2, Plan.getScalarHeader());
-  VPBlockUtils::connectBlocks(VPBB0, VPBB1);
   std::string FullDump;
   raw_string_ostream OS(FullDump);
   Plan.printDOT(OS);
@@ -996,7 +996,7 @@ TEST_F(VPRecipeTest, CastVPInstructionToVPUser) {
   VPValue *Op2 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 2));
   VPInstruction Recipe(Instruction::Add, {Op1, Op2});
 
-  checkVPRecipeCastImpl<VPInstruction, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPInstruction, VPUser, VPIRMetadata>(&Recipe);
 }
 
 TEST_F(VPRecipeTest, CastVPWidenRecipeToVPUser) {
@@ -1011,7 +1011,7 @@ TEST_F(VPRecipeTest, CastVPWidenRecipeToVPUser) {
   Args.push_back(Op2);
   VPWidenRecipe WidenR(*AI, make_range(Args.begin(), Args.end()));
 
-  checkVPRecipeCastImpl<VPWidenRecipe, VPUser>(&WidenR);
+  checkVPRecipeCastImpl<VPWidenRecipe, VPUser, VPIRMetadata>(&WidenR);
   delete AI;
 }
 
@@ -1030,7 +1030,7 @@ TEST_F(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPDef) {
   Args.push_back(CalledFn);
   VPWidenCallRecipe Recipe(Call, Fn, Args);
 
-  checkVPRecipeCastImpl<VPWidenCallRecipe, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPWidenCallRecipe, VPUser, VPIRMetadata>(&Recipe);
 
   VPValue *VPV = &Recipe;
   EXPECT_TRUE(VPV->getDefiningRecipe());
@@ -1056,7 +1056,8 @@ TEST_F(VPRecipeTest, CastVPWidenSelectRecipeToVPUserAndVPDef) {
   VPWidenSelectRecipe WidenSelectR(*SelectI,
                                    make_range(Args.begin(), Args.end()));
 
-  checkVPRecipeCastImpl<VPWidenSelectRecipe, VPUser>(&WidenSelectR);
+  checkVPRecipeCastImpl<VPWidenSelectRecipe, VPUser, VPIRMetadata>(
+      &WidenSelectR);
 
   VPValue *VPV = &WidenSelectR;
   EXPECT_EQ(&WidenSelectR, VPV->getDefiningRecipe());
@@ -1094,7 +1095,7 @@ TEST_F(VPRecipeTest, CastVPWidenCastRecipeToVPUser) {
   VPValue *Op1 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1));
   VPWidenCastRecipe Recipe(Instruction::ZExt, Op1, Int64, *Cast);
 
-  checkVPRecipeCastImpl<VPWidenCastRecipe, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPWidenCastRecipe, VPUser, VPIRMetadata>(&Recipe);
   delete Cast;
 }
 
@@ -1105,7 +1106,7 @@ TEST_F(VPRecipeTest, CastVPWidenIntrinsicRecipeToVPUser) {
   VPValue *Op2 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 2));
   VPWidenIntrinsicRecipe Recipe(Intrinsic::smax, {Op1, Op2}, Int32);
 
-  checkVPRecipeCastImpl<VPWidenIntrinsicRecipe, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPWidenIntrinsicRecipe, VPUser, VPIRMetadata>(&Recipe);
 }
 
 TEST_F(VPRecipeTest, CastVPBlendRecipeToVPUser) {
@@ -1135,7 +1136,7 @@ TEST_F(VPRecipeTest, CastVPInterleaveRecipeToVPUser) {
   InterleaveGroup<Instruction> IG(4, false, Align(4));
   VPInterleaveRecipe Recipe(&IG, Addr, {}, Mask, false, {}, DebugLoc());
 
-  checkVPRecipeCastImpl<VPInterleaveRecipe, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPInterleaveRecipe, VPUser, VPIRMetadata>(&Recipe);
 }
 
 TEST_F(VPRecipeTest, CastVPReplicateRecipeToVPUser) {
@@ -1151,7 +1152,7 @@ TEST_F(VPRecipeTest, CastVPReplicateRecipeToVPUser) {
   auto *Call = CallInst::Create(FTy, PoisonValue::get(FTy));
   VPReplicateRecipe Recipe(Call, make_range(Args.begin(), Args.end()), true);
 
-  checkVPRecipeCastImpl<VPReplicateRecipe, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPReplicateRecipe, VPUser, VPIRMetadata>(&Recipe);
 
   delete Call;
 }
@@ -1175,7 +1176,7 @@ TEST_F(VPRecipeTest, CastVPWidenMemoryRecipeToVPUserAndVPDef) {
   VPValue *Mask = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 2));
   VPWidenLoadRecipe Recipe(*Load, Addr, Mask, true, false, {}, {});
 
-  checkVPRecipeCastImpl<VPWidenLoadRecipe, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPWidenLoadRecipe, VPUser, VPIRMetadata>(&Recipe);
 
   VPValue *VPV = Recipe.getVPSingleValue();
   EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDefiningRecipe()));
@@ -1194,7 +1195,7 @@ TEST_F(VPRecipeTest, CastVPInterleaveEVLRecipeToVPUser) {
   VPInterleaveRecipe BaseRecipe(&IG, Addr, {}, Mask, false, {}, DebugLoc());
   VPInterleaveEVLRecipe Recipe(BaseRecipe, *EVL, Mask);
 
-  checkVPRecipeCastImpl<VPInterleaveEVLRecipe, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPInterleaveEVLRecipe, VPUser, VPIRMetadata>(&Recipe);
 }
 
 TEST_F(VPRecipeTest, CastVPWidenLoadEVLRecipeToVPUser) {
@@ -1209,7 +1210,7 @@ TEST_F(VPRecipeTest, CastVPWidenLoadEVLRecipeToVPUser) {
   VPWidenLoadRecipe BaseLoad(*Load, Addr, Mask, true, false, {}, {});
   VPWidenLoadEVLRecipe Recipe(BaseLoad, Addr, *EVL, Mask);
 
-  checkVPRecipeCastImpl<VPWidenLoadEVLRecipe, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPWidenLoadEVLRecipe, VPUser, VPIRMetadata>(&Recipe);
 
   delete Load;
 }
@@ -1225,7 +1226,7 @@ TEST_F(VPRecipeTest, CastVPWidenStoreRecipeToVPUser) {
   VPValue *Mask = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 2));
   VPWidenStoreRecipe Recipe(*Store, Addr, StoredVal, Mask, true, false, {}, {});
 
-  checkVPRecipeCastImpl<VPWidenStoreRecipe, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPWidenStoreRecipe, VPUser, VPIRMetadata>(&Recipe);
 
   delete Store;
 }
@@ -1244,7 +1245,7 @@ TEST_F(VPRecipeTest, CastVPWidenStoreEVLRecipeToVPUser) {
                                {});
   VPWidenStoreEVLRecipe Recipe(BaseStore, Addr, *EVL, Mask);
 
-  checkVPRecipeCastImpl<VPWidenStoreEVLRecipe, VPUser>(&Recipe);
+  checkVPRecipeCastImpl<VPWidenStoreEVLRecipe, VPUser, VPIRMetadata>(&Recipe);
 
   delete Store;
 }
@@ -1611,12 +1612,18 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
   auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32),
                                        PoisonValue::get(Int32));
   AI->setName("a");
-  VPValue *ExtVPV1 = getPlan().getOrAddLiveIn(ConstantInt::get(Int32, 1));
-  VPValue *ExtVPV2 = getPlan().getOrAddLiveIn(AI);
+  VPlan &Plan = getPlan();
+  VPValue *ExtVPV1 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1));
+  VPValue *ExtVPV2 = Plan.getOrAddLiveIn(AI);
 
   VPInstruction *I1 = new VPInstruction(Instruction::Add, {ExtVPV1, ExtVPV2});
   VPInstruction *I2 = new VPInstruction(Instruction::Mul, {I1, I1});
 
+  // Add instructions to a block in the plan so they have access to Module
+  VPBasicBlock *VPBB = Plan.getEntry();
+  VPBB->appendRecipe(I1);
+  VPBB->appendRecipe(I2);
+
   // Check printing I1.
   {
     // Use EXPECT_EXIT to capture stderr and compare against expected output.
@@ -1628,7 +1635,7 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
           VPV->dump();
           exit(0);
         },
-        testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
+        testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
 
     // Test VPRecipeBase::dump().
     VPRecipeBase *R = I1;
@@ -1637,7 +1644,7 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
           R->dump();
           exit(0);
         },
-        testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
+        testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
 
     // Test VPDef::dump().
     VPDef *D = I1;
@@ -1646,7 +1653,7 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
           D->dump();
           exit(0);
         },
-        testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
+        testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
   }
   // Check printing I2.
   {
@@ -1659,7 +1666,7 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
           VPV->dump();
           exit(0);
         },
-        testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
+        testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
 
     // Test VPRecipeBase::dump().
     VPRecipeBase *R = I2;
@@ -1668,7 +1675,7 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
           R->dump();
           exit(0);
         },
-        testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
+        testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
 
     // Test VPDef::dump().
     VPDef *D = I2;
@@ -1677,11 +1684,9 @@ TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
           D->dump();
           exit(0);
         },
-        testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
+        testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
   }
 
-  delete I2;
-  delete I1;
   delete AI;
 }
 
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h b/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
index 21090c0716d46..84bf3b60b0296 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
@@ -86,11 +86,18 @@ class VPlanTestIRBase : public testing::Test {
 class VPlanTestBase : public testing::Test {
 protected:
   LLVMContext C;
-  std::unique_ptr<BasicBlock> ScalarHeader;
+  std::unique_ptr<Module> M;
+  Function *F;
+  BasicBlock *ScalarHeader;
   SmallVector<std::unique_ptr<VPlan>> Plans;
 
-  VPlanTestBase() : ScalarHeader(BasicBlock::Create(C, "scalar.header")) {
-    BranchInst::Create(&*ScalarHeader, &*ScalarHeader);
+  VPlanTestBase() {
+    M = std::make_unique<Module>("VPlanTest", C);
+    FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), false);
+    F = Function::Create(FTy, GlobalValue::ExternalLinkage, "test_function",
+                         M.get());
+    ScalarHeader = BasicBlock::Create(C, "scalar.header", F);
+    BranchInst::Create(ScalarHeader, ScalarHeader);
   }
 
   VPlan &getPlan() {

@github-actions
Copy link

github-actions bot commented Nov 17, 2025

🐧 Linux x64 Test Results

  • 186387 tests passed
  • 4860 tests skipped

Implement and use debug printing for VPIRMetadata.
@fhahn fhahn force-pushed the vplan-print-metadata branch from 96de4eb to 6c155f6 Compare November 19, 2025 15:50
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.

2 participants