[profcheck] Add indirect call metadata

This commit is contained in:
Mircea Trofin 2025-08-20 18:29:05 -07:00
parent 2c11a83691
commit 0a12548b08
3 changed files with 72 additions and 11 deletions

View File

@ -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))

View File

@ -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"))

View File

@ -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