Skip to content

Commit 9a60841

Browse files
authored
[PGO][profcheck] ignore explicitly cold functions (#151778)
There is a case when branch profile metadata is OK to miss, namely, cold functions. The goal of the RFC (see the referenced issue) is to avoid accidental omission (and, at a later date, corruption) of profile metadata. However, asking cold functions to have all their conditional branches marked with "0" probabilities would be overdoing it. We can just ask cold functions to have an explicit 0 entry count. This patch: - injects an entry count for functions, unless they have one (synthetic or not) - if the entry count is 0, doesn't inject, nor does it verify the rest of the metadata - at verification, if the entry count is missing, it reports an error Issue #147390
1 parent b77f51f commit 9a60841

File tree

7 files changed

+118
-20
lines changed

7 files changed

+118
-20
lines changed

llvm/lib/Transforms/Utils/ProfileVerify.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@
2020
#include "llvm/IR/MDBuilder.h"
2121
#include "llvm/IR/ProfDataUtils.h"
2222
#include "llvm/Support/BranchProbability.h"
23+
#include "llvm/Support/CommandLine.h"
2324

2425
using namespace llvm;
26+
static cl::opt<int64_t>
27+
DefaultFunctionEntryCount("profcheck-default-function-entry-count",
28+
cl::init(1000));
2529
namespace {
2630
class ProfileInjector {
2731
Function &F;
@@ -63,6 +67,19 @@ bool ProfileInjector::inject() {
6367
// will get the same BPI it does if the injector wasn't running.
6468
auto &BPI = FAM.getResult<BranchProbabilityAnalysis>(F);
6569

70+
// Inject a function count if there's none. It's reasonable for a pass to
71+
// want to clear the MD_prof of a function with zero entry count. If the
72+
// original profile (iFDO or AFDO) is empty for a function, it's simpler to
73+
// require assigning it the 0-entry count explicitly than to mark every branch
74+
// as cold (we do want some explicit information in the spirit of what this
75+
// verifier wants to achieve - make dropping / corrupting MD_prof
76+
// unit-testable)
77+
if (!F.getEntryCount(/*AllowSynthetic=*/true))
78+
F.setEntryCount(DefaultFunctionEntryCount);
79+
// If there is an entry count that's 0, then don't bother injecting. We won't
80+
// verify these either.
81+
if (F.getEntryCount(/*AllowSynthetic=*/true)->getCount() == 0)
82+
return false;
6683
bool Changed = false;
6784
for (auto &BB : F) {
6885
auto *Term = getTerminatorBenefitingFromMDProf(BB);
@@ -119,11 +136,20 @@ PreservedAnalyses ProfileInjectorPass::run(Function &F,
119136

120137
PreservedAnalyses ProfileVerifierPass::run(Function &F,
121138
FunctionAnalysisManager &FAM) {
139+
const auto EntryCount = F.getEntryCount(/*AllowSynthetic=*/true);
140+
if (!EntryCount) {
141+
F.getContext().emitError("Profile verification failed: function entry "
142+
"count missing (set to 0 if cold)");
143+
return PreservedAnalyses::all();
144+
}
145+
if (EntryCount->getCount() == 0)
146+
return PreservedAnalyses::all();
122147
for (const auto &BB : F)
123148
if (const auto *Term =
124149
ProfileInjector::getTerminatorBenefitingFromMDProf(BB))
125150
if (!Term->getMetadata(LLVMContext::MD_prof))
126-
F.getContext().emitError("Profile verification failed");
151+
F.getContext().emitError(
152+
"Profile verification failed: branch annotation missing");
127153

128-
return PreservedAnalyses::none();
154+
return PreservedAnalyses::all();
129155
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; Test that prof-inject does not modify existing metadata (incl. "unknown")
2+
3+
; RUN: opt -passes=prof-inject %s -S -o - | FileCheck %s
4+
5+
define void @foo(i32 %i) {
6+
%c = icmp eq i32 %i, 0
7+
br i1 %c, label %yes, label %no, !prof !0
8+
yes:
9+
br i1 %c, label %yes2, label %no, !prof !1
10+
yes2:
11+
ret void
12+
no:
13+
ret void
14+
}
15+
16+
!0 = !{!"branch_weights", i32 1, i32 2}
17+
!1 = !{!"unknown"}
18+
; CHECK: define void @foo(i32 %i) !prof !0
19+
; CHECK: br i1 %c, label %yes, label %no, !prof !1
20+
; CHECK: !0 = !{!"function_entry_count", i64 1000}
21+
; CHECK: !1 = !{!"branch_weights", i32 1, i32 2}
22+
; CHECK: !2 = !{!"unknown"}
Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
; Test that prof-inject only injects missing metadata
22

3-
; RUN: opt -passes=prof-inject %s -S -o - | FileCheck %s
3+
; RUN: opt -passes=prof-inject -profcheck-default-function-entry-count=10 %s -S -o - | FileCheck %s
44

55
define void @foo(i32 %i) {
66
%c = icmp eq i32 %i, 0
@@ -13,8 +13,26 @@ no:
1313
ret void
1414
}
1515

16+
define void @cold(i32 %i) !prof !1 {
17+
%c = icmp eq i32 %i, 0
18+
br i1 %c, label %yes, label %no
19+
yes:
20+
br i1 %c, label %yes2, label %no
21+
yes2:
22+
ret void
23+
no:
24+
ret void
25+
}
1626
!0 = !{!"branch_weights", i32 1, i32 2}
17-
; CHECK: br i1 %c, label %yes, label %no, !prof !0
18-
; CHECK: br i1 %c, label %yes2, label %no, !prof !1
19-
; CHECK: !0 = !{!"branch_weights", i32 1, i32 2}
20-
; CHECK: !1 = !{!"branch_weights", i32 3, i32 5}
27+
!1 = !{!"function_entry_count", i32 0}
28+
29+
; CHECK-LABEL: @foo
30+
; CHECK: br i1 %c, label %yes, label %no, !prof !1
31+
; CHECK: br i1 %c, label %yes2, label %no, !prof !2
32+
; CHECK-LABEL: @cold
33+
; CHECK: br i1 %c, label %yes, label %no{{$}}
34+
; CHECK: br i1 %c, label %yes2, label %no{{$}}
35+
; CHECK: !0 = !{!"function_entry_count", i64 10}
36+
; CHECK: !1 = !{!"branch_weights", i32 1, i32 2}
37+
; CHECK: !2 = !{!"branch_weights", i32 3, i32 5}
38+
; CHECK: !3 = !{!"function_entry_count", i32 0}
Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
; Test that prof-inject does not modify existing metadata (incl. "unknown")
22

3-
; RUN: opt -passes=prof-inject %s -S -o - | FileCheck %s
43
; RUN: opt -passes=prof-verify %s -S --disable-output
54

6-
define void @foo(i32 %i) {
5+
define void @foo(i32 %i) !prof !0 {
76
%c = icmp eq i32 %i, 0
8-
br i1 %c, label %yes, label %no, !prof !0
7+
br i1 %c, label %yes, label %no, !prof !1
98
yes:
10-
br i1 %c, label %yes2, label %no, !prof !1
9+
br i1 %c, label %yes2, label %no, !prof !2
1110
yes2:
1211
ret void
1312
no:
1413
ret void
1514
}
1615

17-
!0 = !{!"branch_weights", i32 1, i32 2}
18-
!1 = !{!"unknown"}
19-
; CHECK: br i1 %c, label %yes, label %no, !prof !0
20-
; CHECK: !0 = !{!"branch_weights", i32 1, i32 2}
21-
; CHECK: !1 = !{!"unknown"}
16+
!0 = !{!"function_entry_count", i32 1}
17+
!1 = !{!"branch_weights", i32 1, i32 2}
18+
!2 = !{!"unknown"}
19+
; CHECK: define void @foo(i32 %i) !prof !0
20+
; CHECK: br i1 %c, label %yes, label %no, !prof !1
21+
; CHECK: !0 = !{!"function_entry_count", i64 1}
22+
; CHECK: !1 = !{!"branch_weights", i32 1, i32 2}
23+
; CHECK: !2 = !{!"unknown"}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
; Test prof-verify for functions explicitly marked as cold
2+
3+
; RUN: opt -passes=prof-inject,prof-verify %s -o - 2>&1 | FileCheck %s
4+
5+
define void @foo(i32 %i) !prof !0 {
6+
%c = icmp eq i32 %i, 0
7+
br i1 %c, label %yes, label %no
8+
yes:
9+
ret void
10+
no:
11+
ret void
12+
}
13+
!0 = !{!"function_entry_count", i32 0}
14+
15+
; CHECK-NOT: Profile verification failed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; Test prof-verify for functions without entry count
2+
3+
; RUN: not opt -passes=prof-verify %s -o - 2>&1 | FileCheck %s
4+
5+
define void @foo(i32 %i) {
6+
%c = icmp eq i32 %i, 0
7+
br i1 %c, label %yes, label %no
8+
yes:
9+
ret void
10+
no:
11+
ret void
12+
}
13+
14+
; CHECK: Profile verification failed: function entry count missing (set to 0 if cold)

llvm/test/Transforms/PGOProfile/prof-verify.ll

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55
; RUN: opt -passes=prof-inject,prof-verify %s --disable-output
66
; RUN: opt -enable-profcheck %s -S -o - | FileCheck %s --check-prefix=INJECT
77

8-
define void @foo(i32 %i) {
8+
define void @foo(i32 %i) !prof !0 {
99
%c = icmp eq i32 %i, 0
1010
br i1 %c, label %yes, label %no
1111
yes:
1212
ret void
1313
no:
1414
ret void
1515
}
16+
!0 = !{!"function_entry_count", i32 1}
1617

17-
; INJECT: br i1 %c, label %yes, label %no, !prof !0
18-
; INJECT: !0 = !{!"branch_weights", i32 3, i32 5}
18+
; INJECT: br i1 %c, label %yes, label %no, !prof !1
19+
; INJECT: !1 = !{!"branch_weights", i32 3, i32 5}
1920

20-
; VERIFY: Profile verification failed
21+
; VERIFY: Profile verification failed: branch annotation missing

0 commit comments

Comments
 (0)