Skip to content

Commit 99e4436

Browse files
committed
pass validator
1 parent 0032148 commit 99e4436

File tree

8 files changed

+213
-0
lines changed

8 files changed

+213
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===- ProfileVerify.h - Verify profile info for testing ----0-----*-C++-*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Inject profile information, as part of tests, to verify passes don't
10+
// accidentally drop it.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
#ifndef LLVM_TRANSFORMS_UTILS_PROFILEVERIFY_H
14+
#define LLVM_TRANSFORMS_UTILS_PROFILEVERIFY_H
15+
16+
#include "llvm/IR/Analysis.h"
17+
#include "llvm/IR/PassManager.h"
18+
19+
namespace llvm {
20+
/// Inject MD_prof metadata where it's missing. Used for testing that passes
21+
/// don't accidentally drop this metadata.
22+
class ProfileInjectorPass : public PassInfoMixin<ProfileInjectorPass> {
23+
public:
24+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
25+
};
26+
27+
/// Checks that MD_prof is present on every instruction that supports it. Used
28+
/// in conjunction with the ProfileInjectorPass. MD_prof "unknown" is considered
29+
/// valid (i.e. !{!"unknown"})
30+
class ProfileVerifierPass : public PassInfoMixin<ProfileVerifierPass> {
31+
public:
32+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
33+
};
34+
35+
} // namespace llvm
36+
#endif

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@
357357
#include "llvm/Transforms/Utils/MoveAutoInit.h"
358358
#include "llvm/Transforms/Utils/NameAnonGlobals.h"
359359
#include "llvm/Transforms/Utils/PredicateInfo.h"
360+
#include "llvm/Transforms/Utils/ProfileVerify.h"
360361
#include "llvm/Transforms/Utils/RelLookupTableConverter.h"
361362
#include "llvm/Transforms/Utils/StripGCRelocates.h"
362363
#include "llvm/Transforms/Utils/StripNonLineTableDebugInfo.h"

llvm/lib/Passes/PassRegistry.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,8 @@ FUNCTION_PASS("print<regions>", RegionInfoPrinterPass(errs()))
517517
FUNCTION_PASS("print<scalar-evolution>", ScalarEvolutionPrinterPass(errs()))
518518
FUNCTION_PASS("print<stack-safety-local>", StackSafetyPrinterPass(errs()))
519519
FUNCTION_PASS("print<uniformity>", UniformityInfoPrinterPass(errs()))
520+
FUNCTION_PASS("prof-inject", ProfileInjectorPass())
521+
FUNCTION_PASS("prof-verify", ProfileVerifierPass())
520522
FUNCTION_PASS("reassociate", ReassociatePass())
521523
FUNCTION_PASS("redundant-dbg-inst-elim", RedundantDbgInstEliminationPass())
522524
FUNCTION_PASS("reg2mem", RegToMemPass())

llvm/lib/Transforms/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ add_llvm_component_library(LLVMTransformUtils
6767
MoveAutoInit.cpp
6868
NameAnonGlobals.cpp
6969
PredicateInfo.cpp
70+
ProfileVerify.cpp
7071
PromoteMemoryToRegister.cpp
7172
RelLookupTableConverter.cpp
7273
ScalarEvolutionExpander.cpp
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//===- ProfileVerify.cpp - Verify profile info for testing ----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/Transforms/Utils/ProfileVerify.h"
10+
#include "llvm/ADT/DynamicAPInt.h"
11+
#include "llvm/ADT/PostOrderIterator.h"
12+
#include "llvm/ADT/STLExtras.h"
13+
#include "llvm/Analysis/BranchProbabilityInfo.h"
14+
#include "llvm/Analysis/LoopInfo.h"
15+
#include "llvm/IR/Analysis.h"
16+
#include "llvm/IR/Dominators.h"
17+
#include "llvm/IR/Function.h"
18+
#include "llvm/IR/LLVMContext.h"
19+
#include "llvm/IR/MDBuilder.h"
20+
#include "llvm/IR/ProfDataUtils.h"
21+
#include "llvm/Support/BranchProbability.h"
22+
23+
using namespace llvm;
24+
namespace {
25+
class ProfileInjector {
26+
Function &F;
27+
FunctionAnalysisManager &FAM;
28+
29+
public:
30+
static bool supportsBranchWeights(const Instruction &I) {
31+
return isa<BranchInst>(&I) ||
32+
33+
isa<SwitchInst>(&I) ||
34+
35+
isa<IndirectBrInst>(&I) || isa<SelectInst>(&I) ||
36+
isa<CallBrInst>(&I);
37+
}
38+
39+
ProfileInjector(Function &F, FunctionAnalysisManager &FAM) : F(F), FAM(FAM) {}
40+
bool inject();
41+
};
42+
} // namespace
43+
44+
bool ProfileInjector::inject() {
45+
auto &BPI = FAM.getResult<BranchProbabilityAnalysis>(F);
46+
47+
for (auto &BB : F) {
48+
if (succ_size(&BB) <= 1)
49+
continue;
50+
auto *Term = BB.getTerminator();
51+
assert(Term);
52+
if (Term->getMetadata(LLVMContext::MD_prof) ||
53+
!supportsBranchWeights(*Term))
54+
continue;
55+
SmallVector<BranchProbability> Probs;
56+
Probs.reserve(Term->getNumSuccessors());
57+
for (auto I = 0U, E = Term->getNumSuccessors(); I < E; ++I)
58+
Probs.emplace_back(BPI.getEdgeProbability(&BB, Term->getSuccessor(I)));
59+
60+
const auto *FirstZeroDenominator =
61+
find_if(Probs, [](const BranchProbability &P) {
62+
return P.getDenominator() == 0;
63+
});
64+
assert(FirstZeroDenominator == Probs.end());
65+
const auto *FirstNonzeroNumerator =
66+
find_if(Probs, [](const BranchProbability &P) {
67+
return P.getNumerator() != 0;
68+
});
69+
assert(FirstNonzeroNumerator != Probs.end());
70+
DynamicAPInt LCM(Probs[0].getDenominator());
71+
DynamicAPInt GCD(FirstNonzeroNumerator->getNumerator());
72+
for (const auto &Prob : drop_begin(Probs)) {
73+
if (!Prob.getNumerator())
74+
continue;
75+
LCM = llvm::lcm(LCM, DynamicAPInt(Prob.getDenominator()));
76+
GCD = llvm::lcm(GCD, DynamicAPInt(Prob.getNumerator()));
77+
}
78+
SmallVector<uint32_t> Weights;
79+
Weights.reserve(Term->getNumSuccessors());
80+
for (const auto &Prob : Probs) {
81+
auto W = Prob.getNumerator() * LCM / GCD;
82+
Weights.emplace_back(static_cast<int32_t>((int64_t)W));
83+
}
84+
setBranchWeights(*Term, Weights, false);
85+
}
86+
return true;
87+
}
88+
89+
PreservedAnalyses ProfileInjectorPass::run(Function &F,
90+
FunctionAnalysisManager &FAM) {
91+
ProfileInjector PI(F, FAM);
92+
if (!PI.inject())
93+
return PreservedAnalyses::all();
94+
95+
return PreservedAnalyses::none();
96+
}
97+
98+
PreservedAnalyses ProfileVerifierPass::run(Function &F,
99+
FunctionAnalysisManager &FAM) {
100+
bool Changed = false;
101+
for (auto &BB : F)
102+
if (succ_size(&BB) >= 2)
103+
if (auto *Term = BB.getTerminator())
104+
if (ProfileInjector::supportsBranchWeights(*Term)) {
105+
if (!Term->getMetadata(LLVMContext::MD_prof)) {
106+
F.getContext().emitError("Profile verification failed");
107+
} else {
108+
Changed = true;
109+
}
110+
}
111+
112+
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
113+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
; Test that prof-inject only injects missing metadata
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
10+
yes2:
11+
ret void
12+
no:
13+
ret void
14+
}
15+
16+
!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 429496729, i32 715827882}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
; Test that prof-verify does not modify existing metadata (incl. "unknown")
2+
3+
; RUN: opt -passes=prof-inject %s -S -o - | FileCheck %s
4+
; RUN: opt -passes=prof-verify %s -S --disable-output
5+
6+
define void @foo(i32 %i) {
7+
%c = icmp eq i32 %i, 0
8+
br i1 %c, label %yes, label %no, !prof !0
9+
yes:
10+
br i1 %c, label %yes2, label %no, !prof !1
11+
yes2:
12+
ret void
13+
no:
14+
ret void
15+
}
16+
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"}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
; Test prof-inject and prof-verify
2+
3+
; RUN: opt -passes=prof-inject %s -S -o - | FileCheck %s --check-prefix=INJECT
4+
; RUN: not opt -passes=prof-verify %s -S -o - 2>&1 | FileCheck %s --check-prefix=VERIFY
5+
; RUN: opt -passes=prof-inject,prof-verify %s --disable-output
6+
7+
define void @foo(i32 %i) {
8+
%c = icmp eq i32 %i, 0
9+
br i1 %c, label %yes, label %no
10+
yes:
11+
ret void
12+
no:
13+
ret void
14+
}
15+
16+
; INJECT: br i1 %c, label %yes, label %no, !prof !0
17+
; INJECT: !0 = !{!"branch_weights", i32 429496729, i32 715827882}
18+
19+
; VERIFY: Profile verification failed

0 commit comments

Comments
 (0)