[llvm] [profcheck] Add indirect call metadata (PR #154657)
Mircea Trofin via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 20 21:26:12 PDT 2025
https://github.com/mtrofin updated https://github.com/llvm/llvm-project/pull/154657
>From 0a12548b08d6f89704f4e988f0b4364ccc076263 Mon Sep 17 00:00:00 2001
From: Mircea Trofin <mtrofin at google.com>
Date: Wed, 20 Aug 2025 18:29:05 -0700
Subject: [PATCH] [profcheck] Add indirect call metadata
---
llvm/lib/Transforms/Utils/ProfileVerify.cpp | 44 ++++++++++++++-----
.../JumpTableToSwitch/lit.local.cfg | 5 +++
.../PGOProfile/profcheck-indirect-calls.ll | 34 ++++++++++++++
3 files changed, 72 insertions(+), 11 deletions(-)
create mode 100644 llvm/test/Transforms/JumpTableToSwitch/lit.local.cfg
create mode 100644 llvm/test/Transforms/PGOProfile/profcheck-indirect-calls.ll
diff --git a/llvm/lib/Transforms/Utils/ProfileVerify.cpp b/llvm/lib/Transforms/Utils/ProfileVerify.cpp
index 41647f7717a43..cf8d6c043e0cd 100644
--- a/llvm/lib/Transforms/Utils/ProfileVerify.cpp
+++ b/llvm/lib/Transforms/Utils/ProfileVerify.cpp
@@ -17,6 +17,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/ProfDataUtils.h"
+#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/BranchProbability.h"
#include "llvm/Support/CommandLine.h"
@@ -36,6 +37,10 @@ static cl::opt<uint32_t> SelectFalseWeight(
"profcheck-default-select-false-weight", cl::init(3U),
cl::desc("When annotating `select` instructions, this value will be used "
"for the second ('false') case."));
+static cl::opt<bool> AnnotateIndirectCalls(
+ "profcheck-annotate-indirect-calls", cl::init(true),
+ cl::desc("Also inject (if missing) MD_prof for indirect calls"));
+
namespace {
class ProfileInjector {
Function &F;
@@ -92,12 +97,24 @@ bool ProfileInjector::inject() {
return false;
bool Changed = false;
for (auto &BB : F) {
- if (AnnotateSelect) {
- for (auto &I : BB) {
- if (isa<SelectInst>(I) && !I.getMetadata(LLVMContext::MD_prof))
- setBranchWeights(I, {SelectTrueWeight, SelectFalseWeight},
- /*IsExpected=*/false);
- }
+ for (auto &I : BB) {
+ // Annotate instructions that support MD_prof metadata, such as `select`
+ // and indirect calls - *if* they don't already have that metadata.
+ if (AnnotateSelect && isa<SelectInst>(I) &&
+ !I.getMetadata(LLVMContext::MD_prof))
+ setBranchWeights(I, {SelectTrueWeight, SelectFalseWeight},
+ /*IsExpected=*/false);
+ if (AnnotateIndirectCalls)
+ if (auto *CB = dyn_cast<CallBase>(&I))
+ if (CB->isIndirectCall() && !CB->getMetadata(LLVMContext::MD_prof))
+ // add a valid-format but bogus indirect call profile. Neither the
+ // GUIDs nor the counts are meant to matter.
+ annotateValueSite(*F.getParent(), *CB,
+ {{/*.Value=*/2345, /*.Count=*/10},
+ {/*.Value=*/5678, /*.Count=*/20}},
+ /*Sum=*/30,
+ InstrProfValueKind::IPVK_IndirectCallTarget,
+ /*MaxMDCount=*/30);
}
auto *Term = getTerminatorBenefitingFromMDProf(BB);
if (!Term || Term->getMetadata(LLVMContext::MD_prof))
@@ -162,11 +179,16 @@ PreservedAnalyses ProfileVerifierPass::run(Function &F,
if (EntryCount->getCount() == 0)
return PreservedAnalyses::all();
for (const auto &BB : F) {
- if (AnnotateSelect) {
- for (const auto &I : BB)
- if (isa<SelectInst>(I) && !I.getMetadata(LLVMContext::MD_prof))
- F.getContext().emitError(
- "Profile verification failed: select annotation missing");
+ for (const auto &I : BB) {
+ if (AnnotateSelect && isa<SelectInst>(I) &&
+ !I.getMetadata(LLVMContext::MD_prof))
+ F.getContext().emitError(
+ "Profile verification failed: select annotation missing");
+ if (AnnotateIndirectCalls)
+ if (const auto *CB = dyn_cast<CallBase>(&I))
+ if (CB->isIndirectCall() && !I.getMetadata(LLVMContext::MD_prof))
+ F.getContext().emitError("Profile verification failed: indirect "
+ "call annotation missing");
}
if (const auto *Term =
ProfileInjector::getTerminatorBenefitingFromMDProf(BB))
diff --git a/llvm/test/Transforms/JumpTableToSwitch/lit.local.cfg b/llvm/test/Transforms/JumpTableToSwitch/lit.local.cfg
new file mode 100644
index 0000000000000..de5b8ebb5d427
--- /dev/null
+++ b/llvm/test/Transforms/JumpTableToSwitch/lit.local.cfg
@@ -0,0 +1,5 @@
+if bool(config.enable_profcheck):
+ # disable indirect call annotations here. The targets for JumpTableToSwitch
+ # are specific, and the profile injector is (intentionally) naive in what
+ # VP metadata it inserts.
+ config.substitutions.append(("opt", "opt -profcheck-annotate-indirect-calls=0"))
\ No newline at end of file
diff --git a/llvm/test/Transforms/PGOProfile/profcheck-indirect-calls.ll b/llvm/test/Transforms/PGOProfile/profcheck-indirect-calls.ll
new file mode 100644
index 0000000000000..027395eff7515
--- /dev/null
+++ b/llvm/test/Transforms/PGOProfile/profcheck-indirect-calls.ll
@@ -0,0 +1,34 @@
+; Check insertion and verification of indirect calls
+; RUN: split-file %s %t
+; RUN: opt -passes=prof-inject %t/inject.ll -S -o - | FileCheck %t/inject.ll
+; RUN: opt -passes=prof-verify %t/verify-ok.ll -S -o - | FileCheck %t/verify-ok.ll
+; RUN: not opt -passes=prof-verify %t/verify-bad.ll -S -o - 2>&1 | FileCheck %t/verify-bad.ll
+
+;--- inject.ll
+define void @foo(ptr %f) {
+ call void %f()
+ ret void
+}
+
+; CHECK: call void %f(), !prof !1
+; CHECK: !0 = !{!"function_entry_count", i64 1000}
+; CHECK: !1 = !{!"VP", i32 0, i64 30, i64 2345, i64 10, i64 5678, i64 20}
+
+;--- verify-ok.ll
+define void @foo(ptr %f) !prof !0 {
+ call void %f(), !prof !1
+ ret void
+}
+!0 = !{!"function_entry_count", i64 10}
+!1 = !{!"VP", i32 0, i64 100, i64 123, i64 50, i64 456, i64 50}
+
+; CHECK: call void %f(), !prof !1
+; CHECK: !1 = !{!"VP", i32 0, i64 100, i64 123, i64 50, i64 456, i64 50}
+
+;--- verify-bad.ll
+define void @foo(ptr %f) !prof !0 {
+ call void %f()
+ ret void
+}
+!0 = !{!"function_entry_count", i64 10}
+; CHECK: Profile verification failed: indirect call annotation missing
More information about the llvm-commits
mailing list