[llvm] [IR][PGO] Verify the structure of `VP` metadata. (PR #145584)

Mircea Trofin via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 30 10:05:39 PDT 2025


https://github.com/mtrofin updated https://github.com/llvm/llvm-project/pull/145584

>From 63d1f530feeabf8e146d9b5624a5cae080adc8b5 Mon Sep 17 00:00:00 2001
From: Mircea Trofin <mtrofin at google.com>
Date: Tue, 24 Jun 2025 13:14:09 -0700
Subject: [PATCH] [IR][PGO] Verify the structure of `VP` metadata.

---
 llvm/include/llvm/IR/ProfDataUtils.h |  3 +++
 llvm/lib/IR/ProfDataUtils.cpp        |  2 +-
 llvm/lib/IR/Verifier.cpp             | 23 +++++++++++++++--
 llvm/test/Verifier/value-profile.ll  | 38 ++++++++++++++++++++++++++++
 4 files changed, 63 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/Verifier/value-profile.ll

diff --git a/llvm/include/llvm/IR/ProfDataUtils.h b/llvm/include/llvm/IR/ProfDataUtils.h
index 5c0e08b03c245..c24b2aa19a407 100644
--- a/llvm/include/llvm/IR/ProfDataUtils.h
+++ b/llvm/include/llvm/IR/ProfDataUtils.h
@@ -35,6 +35,9 @@ LLVM_ABI bool hasProfMD(const Instruction &I);
 /// Checks if an MDNode contains Branch Weight Metadata
 LLVM_ABI bool isBranchWeightMD(const MDNode *ProfileData);
 
+/// Checks if an MDNode contains value profiling Metadata
+LLVM_ABI bool isValueProfileMD(const MDNode *ProfileData);
+
 /// Checks if an instructions has Branch Weight Metadata
 ///
 /// \param I The instruction to check
diff --git a/llvm/lib/IR/ProfDataUtils.cpp b/llvm/lib/IR/ProfDataUtils.cpp
index 740023ca6d23b..605208edda70a 100644
--- a/llvm/lib/IR/ProfDataUtils.cpp
+++ b/llvm/lib/IR/ProfDataUtils.cpp
@@ -103,7 +103,7 @@ bool isBranchWeightMD(const MDNode *ProfileData) {
   return isTargetMD(ProfileData, MDProfLabels::BranchWeights, MinBWOps);
 }
 
-static bool isValueProfileMD(const MDNode *ProfileData) {
+bool isValueProfileMD(const MDNode *ProfileData) {
   return isTargetMD(ProfileData, MDProfLabels::ValueProfile, MinVPOps);
 }
 
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 96eb4eff8dc11..853f3b45fd10c 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -112,6 +112,7 @@
 #include "llvm/IR/Value.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
+#include "llvm/ProfileData/InstrProf.h"
 #include "llvm/Support/AMDGPUAddrSpace.h"
 #include "llvm/Support/AtomicOrdering.h"
 #include "llvm/Support/Casting.h"
@@ -5032,9 +5033,27 @@ void Verifier::visitProfMetadata(Instruction &I, MDNode *MD) {
       Check(mdconst::dyn_extract<ConstantInt>(MDO),
             "!prof brunch_weights operand is not a const int");
     }
+  } else if (ProfName == MDProfLabels::ValueProfile) {
+    Check(isValueProfileMD(MD), "invalid value profiling metadata", MD);
+    ConstantInt *KindInt = mdconst::dyn_extract<ConstantInt>(MD->getOperand(1));
+    Check(KindInt, "VP !prof missing kind argument", MD);
+
+    auto Kind = KindInt->getZExtValue();
+    Check(Kind >= InstrProfValueKind::IPVK_First &&
+              Kind <= InstrProfValueKind::IPVK_Last,
+          "Invalid VP !prof kind", MD);
+    Check(MD->getNumOperands() % 2 == 1,
+          "VP !prof should have an even number "
+          "of arguments after 'VP'",
+          MD);
+    if (Kind == InstrProfValueKind::IPVK_IndirectCallTarget ||
+        Kind == InstrProfValueKind::IPVK_MemOPSize)
+      Check(isa<CallBase>(I),
+            "VP !prof indirect call or memop size expected to be applied to "
+            "CallBase instructions only",
+            MD);
   } else {
-    Check(ProfName == MDProfLabels::ValueProfile,
-          "expected either branch_weights or VP profile name", MD);
+    CheckFailed("expected either branch_weights or VP profile name", MD);
   }
 }
 
diff --git a/llvm/test/Verifier/value-profile.ll b/llvm/test/Verifier/value-profile.ll
new file mode 100644
index 0000000000000..f38bc7728a703
--- /dev/null
+++ b/llvm/test/Verifier/value-profile.ll
@@ -0,0 +1,38 @@
+; Test MD_prof "VP" validation
+
+; RUN: split-file %s %t
+; RUN: opt -passes=verify %t/valid.ll --disable-output
+; RUN: not opt -passes=verify %t/invalid-kind.ll --disable-output 2>&1 | FileCheck %s --check-prefix=INVALID-KIND
+; RUN: not opt -passes=verify %t/invalid-count.ll --disable-output 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT
+; RUN: not opt -passes=verify %t/invalid-place.ll --disable-output 2>&1 | FileCheck %s --check-prefix=INVALID-PLACE
+
+;--- valid.ll
+define void @test(ptr %0) {
+  call void %0(), !prof !0
+  ret void
+}
+!0 = !{!"VP", i32 0, i32 20, i64 1234, i64 10, i64 5678, i64 5}
+
+;--- invalid-kind.ll
+define void @test(ptr %0) {
+  call void %0(), !prof !0
+  ret void
+}
+!0 = !{!"VP", i32 3, i32 20, i64 1234, i64 10, i64 5678, i64 5}
+; INVALID-KIND: Invalid VP !prof kind
+
+;--- invalid-count.ll
+define void @test(ptr %0) {
+  call void %0(), !prof !0
+  ret void
+}
+!0 = !{!"VP", i32 1, i64 1234, i64 10, i64 5678, i64 5}
+; INVALID-COUNT: VP !prof should have an even number of arguments after 'VP'
+
+;--- invalid-place.ll
+define i32 @test(i32 %0) {
+  %r = add i32 %0, 1, !prof !0
+  ret i32 %r
+}
+!0 = !{!"VP", i32 1, i32 20, i64 1234, i64 10, i64 5678, i64 5}
+; INVALID-PLACE: VP !prof indirect call or memop size expected to be applied to CallBase instructions only



More information about the llvm-commits mailing list