From 63d1f530feeabf8e146d9b5624a5cae080adc8b5 Mon Sep 17 00:00:00 2001 From: Mircea Trofin 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(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(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(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