Skip to content

Commit 3df59d9

Browse files
committed
pass validator
1 parent 0032148 commit 3df59d9

File tree

8 files changed

+217
-0
lines changed

8 files changed

+217
-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 ----------*-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: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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/Instructions.h"
19+
#include "llvm/IR/LLVMContext.h"
20+
#include "llvm/IR/MDBuilder.h"
21+
#include "llvm/IR/ProfDataUtils.h"
22+
#include "llvm/Support/BranchProbability.h"
23+
24+
using namespace llvm;
25+
namespace {
26+
class ProfileInjector {
27+
Function &F;
28+
FunctionAnalysisManager &FAM;
29+
30+
public:
31+
static const Instruction *
32+
getTerminatorBenefitingFromMDProf(const BasicBlock &BB) {
33+
if (succ_size(&BB) < 2)
34+
return nullptr;
35+
auto *Term = BB.getTerminator();
36+
return (isa<BranchInst>(Term) || isa<SwitchInst>(Term) ||
37+
isa<IndirectBrInst>(Term) || isa<CallBrInst>(Term))
38+
? Term
39+
: nullptr;
40+
}
41+
42+
static Instruction *getTerminatorBenefitingFromMDProf(BasicBlock &BB) {
43+
return const_cast<Instruction *>(
44+
getTerminatorBenefitingFromMDProf(const_cast<const BasicBlock &>(BB)));
45+
}
46+
47+
ProfileInjector(Function &F, FunctionAnalysisManager &FAM) : F(F), FAM(FAM) {}
48+
bool inject();
49+
};
50+
} // namespace
51+
52+
// FIXME: currently this injects only for terminators. Select isn't yet
53+
// supported.
54+
bool ProfileInjector::inject() {
55+
auto &BPI = FAM.getResult<BranchProbabilityAnalysis>(F);
56+
57+
bool Changed = false;
58+
for (auto &BB : F) {
59+
auto *Term = getTerminatorBenefitingFromMDProf(BB);
60+
if (!Term || Term->getMetadata(LLVMContext::MD_prof))
61+
continue;
62+
SmallVector<BranchProbability> Probs;
63+
Probs.reserve(Term->getNumSuccessors());
64+
for (auto I = 0U, E = Term->getNumSuccessors(); I < E; ++I)
65+
Probs.emplace_back(BPI.getEdgeProbability(&BB, Term->getSuccessor(I)));
66+
67+
const auto *FirstZeroDenominator =
68+
find_if(Probs, [](const BranchProbability &P) {
69+
return P.getDenominator() == 0;
70+
});
71+
(void)FirstZeroDenominator;
72+
assert(FirstZeroDenominator == Probs.end());
73+
const auto *FirstNonZeroNumerator =
74+
find_if(Probs, [](const BranchProbability &P) {
75+
return !P.isZero() && !P.isUnknown();
76+
});
77+
assert(FirstNonZeroNumerator != Probs.end());
78+
DynamicAPInt LCM(Probs[0].getDenominator());
79+
DynamicAPInt GCD(FirstNonZeroNumerator->getNumerator());
80+
for (const auto &Prob : drop_begin(Probs)) {
81+
if (!Prob.getNumerator())
82+
continue;
83+
LCM = llvm::lcm(LCM, DynamicAPInt(Prob.getDenominator()));
84+
GCD = llvm::gcd(GCD, DynamicAPInt(Prob.getNumerator()));
85+
}
86+
SmallVector<uint32_t> Weights;
87+
Weights.reserve(Term->getNumSuccessors());
88+
for (const auto &Prob : Probs) {
89+
DynamicAPInt W =
90+
(Prob.getNumerator() * LCM / GCD) / Prob.getDenominator();
91+
Weights.emplace_back(static_cast<uint32_t>((int64_t)W));
92+
}
93+
setBranchWeights(*Term, Weights, /*IsExpected=*/false);
94+
Changed = true;
95+
}
96+
return Changed;
97+
}
98+
99+
PreservedAnalyses ProfileInjectorPass::run(Function &F,
100+
FunctionAnalysisManager &FAM) {
101+
ProfileInjector PI(F, FAM);
102+
if (!PI.inject())
103+
return PreservedAnalyses::all();
104+
105+
return PreservedAnalyses::none();
106+
}
107+
108+
PreservedAnalyses ProfileVerifierPass::run(Function &F,
109+
FunctionAnalysisManager &FAM) {
110+
for (const auto &BB : F)
111+
if (const auto *Term =
112+
ProfileInjector::getTerminatorBenefitingFromMDProf(BB))
113+
if (!Term->getMetadata(LLVMContext::MD_prof))
114+
F.getContext().emitError("Profile verification failed");
115+
116+
return PreservedAnalyses::none();
117+
}
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 3, i32 5}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
; 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 3, i32 5}
18+
19+
; VERIFY: Profile verification failed

0 commit comments

Comments
 (0)