summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMircea Trofin <mtrofin@google.com>2025-08-20 18:29:05 -0700
committerMircea Trofin <mtrofin@google.com>2025-08-20 21:25:50 -0700
commit0a12548b08d6f89704f4e988f0b4364ccc076263 (patch)
treeb2066fe40eebb6acb0889d497ae5b43d2f0f2d51
parent2c11a83691b7089d7a79e9f122dc521e6ea7e51e (diff)
[profcheck] Add indirect call metadatausers/mtrofin/08-20-_profcheck_add_indirect_call_metadata
-rw-r--r--llvm/lib/Transforms/Utils/ProfileVerify.cpp44
-rw-r--r--llvm/test/Transforms/JumpTableToSwitch/lit.local.cfg5
-rw-r--r--llvm/test/Transforms/PGOProfile/profcheck-indirect-calls.ll34
3 files changed, 72 insertions, 11 deletions
diff --git a/llvm/lib/Transforms/Utils/ProfileVerify.cpp b/llvm/lib/Transforms/Utils/ProfileVerify.cpp
index 41647f7717a4..cf8d6c043e0c 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 000000000000..de5b8ebb5d42
--- /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 000000000000..027395eff751
--- /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