[llvm] [VPlan] Implement printing VPIRMetadata. (PR #165825)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Sun Nov 2 07:18:48 PST 2025
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/165825
>From 6cf1ed5b7c1563818af16a7c143cd8b47fdad2f1 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] [VPlan] Implement printing VPIRMetadata.
Implement and use debug printing for VPIRMetadata.
---
llvm/lib/Transforms/Vectorize/VPlan.h | 11 ++++++
.../lib/Transforms/Vectorize/VPlanRecipes.cpp | 33 ++++++++++++++++++
.../LoopVectorize/vplan-printing-metadata.ll | 18 +++++-----
.../Transforms/Vectorize/VPlanTest.cpp | 34 +++++++++++--------
.../Transforms/Vectorize/VPlanTestBase.h | 15 +++++---
5 files changed, 83 insertions(+), 28 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 9081ad7db9427..3cf3215c14ae9 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -968,6 +968,12 @@ class VPIRMetadata {
/// Intersect this VPIRMetada object with \p MD, keeping only metadata
/// nodes that are common to both.
void intersect(const VPIRMetadata &MD);
+
+ /// Print metadata with node IDs.
+ void print(raw_ostream &O, const Module &M) const;
+
+ /// Return true if there is any metadata to print.
+ bool empty() const { return Metadata.empty(); }
};
/// This is a concrete Recipe that models a single VPlan-level instruction.
@@ -4282,6 +4288,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 1a02117061caa..2870b24389cb0 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1443,6 +1443,8 @@ void VPInstruction::print(raw_ostream &O, const Twine &Indent,
printFlags(O);
printOperands(O, SlotTracker);
+ if (!VPIRMetadata::empty())
+ VPIRMetadata::print(O, getParent()->getPlan()->getModule());
if (auto DL = getDebugLoc()) {
O << ", !dbg ";
@@ -1669,6 +1671,25 @@ void VPIRMetadata::intersect(const VPIRMetadata &Other) {
Metadata = std::move(MetadataIntersection);
}
+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 << ")";
+}
+
void VPWidenCallRecipe::execute(VPTransformState &State) {
assert(State.VF.isVector() && "not widening");
assert(Variant != nullptr && "Can't create vector function.");
@@ -1729,6 +1750,8 @@ void VPWidenCallRecipe::print(raw_ostream &O, const Twine &Indent,
Op->printAsOperand(O, SlotTracker);
});
O << ")";
+ if (!VPIRMetadata::empty())
+ VPIRMetadata::print(O, getParent()->getPlan()->getModule());
O << " (using library function";
if (Variant->hasName())
@@ -1863,6 +1886,8 @@ void VPWidenIntrinsicRecipe::print(raw_ostream &O, const Twine &Indent,
Op->printAsOperand(O, SlotTracker);
});
O << ")";
+ if (!VPIRMetadata::empty())
+ VPIRMetadata::print(O, getParent()->getPlan()->getModule());
}
#endif
@@ -2255,6 +2280,8 @@ void VPWidenRecipe::print(raw_ostream &O, const Twine &Indent,
O << " = " << Instruction::getOpcodeName(Opcode);
printFlags(O);
printOperands(O, SlotTracker);
+ if (!VPIRMetadata::empty())
+ VPIRMetadata::print(O, getParent()->getPlan()->getModule());
}
#endif
@@ -2336,6 +2363,8 @@ void VPWidenCastRecipe::print(raw_ostream &O, const Twine &Indent,
printFlags(O);
printOperands(O, SlotTracker);
O << " to " << *getResultType();
+ if (!VPIRMetadata::empty())
+ VPIRMetadata::print(O, getParent()->getPlan()->getModule());
}
#endif
@@ -3617,6 +3646,8 @@ void VPWidenLoadRecipe::print(raw_ostream &O, const Twine &Indent,
printAsOperand(O, SlotTracker);
O << " = load ";
printOperands(O, SlotTracker);
+ if (!VPIRMetadata::empty())
+ VPIRMetadata::print(O, getParent()->getPlan()->getModule());
}
#endif
@@ -3738,6 +3769,8 @@ void VPWidenStoreRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "WIDEN store ";
printOperands(O, SlotTracker);
+ if (!VPIRMetadata::empty())
+ VPIRMetadata::print(O, getParent()->getPlan()->getModule());
}
#endif
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 59a9ea1a720b3..49fedc83ce9b0 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
@@ -731,18 +731,18 @@ 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);
- VPSlotTracker SlotTracker;
+ VPSlotTracker SlotTracker(&Plan);
I3->print(OS, "", SlotTracker);
- EXPECT_EQ("EMIT br <badref>, <badref>", I3Dump);
+ EXPECT_EQ("EMIT br vp<%2>, vp<%3>", I3Dump);
}
- VPBlockUtils::connectBlocks(VPBB2, Plan.getScalarHeader());
- VPBlockUtils::connectBlocks(VPBB0, VPBB1);
std::string FullDump;
raw_string_ostream OS(FullDump);
Plan.printDOT(OS);
@@ -1509,12 +1509,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.
@@ -1526,7 +1532,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;
@@ -1535,7 +1541,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;
@@ -1544,7 +1550,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.
{
@@ -1557,7 +1563,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;
@@ -1566,7 +1572,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;
@@ -1575,11 +1581,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 ed6e13b4add3d..f763b3465de36 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
@@ -86,15 +86,22 @@ 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(VPValue *TC = nullptr) {
- Plans.push_back(std::make_unique<VPlan>(&*ScalarHeader, TC));
+ Plans.push_back(std::make_unique<VPlan>(ScalarHeader, TC));
return *Plans.back();
}
};
More information about the llvm-commits
mailing list