[llvm] [VPlan] Implement printing VPIRMetadata. (PR #168385)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 17 12:57:53 PST 2025
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/168385
>From 7aa511d1b2e62b7576b2c2cd5a6b7aadaa5d4377 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 17 Nov 2025 15:12:29 +0000
Subject: [PATCH 1/2] [VPlan] Cast VPIRMetadata.
---
llvm/lib/Transforms/Vectorize/VPlan.h | 71 +++++++++++++++++++
.../Transforms/Vectorize/VPlanTest.cpp | 27 +++----
2 files changed, 85 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 0932922c07126..ce7455ec5b1fb 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -3871,6 +3871,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.
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
index ee7fa175ca918..2d35c88b1d23f 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
@@ -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;
}
>From 96de4eb6d03e1543ab7aa46bce842f05a7ef0c02 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 31 Oct 2025 04:34:53 +0000
Subject: [PATCH 2/2] [VPlan] Implement printing VPIRMetadata.
Implement and use debug printing for VPIRMetadata.
!fixup address comments, thanks!
---
llvm/lib/Transforms/Vectorize/VPlan.h | 10 +++++++
.../lib/Transforms/Vectorize/VPlanRecipes.cpp | 27 +++++++++++++++++++
.../LoopVectorize/vplan-printing-metadata.ll | 18 ++++++-------
3 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index ce7455ec5b1fb..95829e03dca25 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 VPlan *Plan) const;
+#endif
};
/// This is a concrete Recipe that models a single VPlan-level instruction.
@@ -4406,6 +4411,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 e2a8e495d5ed5..05812f887ef52 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -489,6 +489,11 @@ 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)) {
+ if (const VPBasicBlock *Parent = getParent())
+ Metadata->print(O, Parent->getPlan());
+ }
}
#endif
@@ -1703,6 +1708,28 @@ void VPIRMetadata::intersect(const VPIRMetadata &Other) {
Metadata = std::move(MetadataIntersection);
}
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+void VPIRMetadata::print(raw_ostream &O, const VPlan *Plan) const {
+ if (Metadata.empty() || !Plan)
+ return;
+
+ const Module &M = Plan->getModule();
+ 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
More information about the llvm-commits
mailing list