1//===- OptimizationRemarkEmitter.cpp - Optimization Diagnostic --*- 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// Optimization diagnostic interfaces. It's packaged as an analysis pass so
10// that by using this service passes become dependent on BFI as well. BFI is
11// used to compute the "hotness" of the diagnostic message.
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Analysis/OptimizationRemarkEmitter.h"
15#include "llvm/Analysis/BranchProbabilityInfo.h"
16#include "llvm/Analysis/LazyBlockFrequencyInfo.h"
17#include "llvm/Analysis/LoopInfo.h"
18#include "llvm/Analysis/ProfileSummaryInfo.h"
19#include "llvm/IR/DiagnosticInfo.h"
20#include "llvm/IR/Dominators.h"
21#include "llvm/IR/LLVMContext.h"
22#include "llvm/InitializePasses.h"
23#include <optional>
24
25using namespace llvm;
26
27OptimizationRemarkEmitter::OptimizationRemarkEmitter(const Function *F)
28 : F(F), BFI(nullptr) {
29 if (!F->getContext().getDiagnosticsHotnessRequested())
30 return;
31
32 // First create a dominator tree.
33 DominatorTree DT;
34 DT.recalculate(Func&: *const_cast<Function *>(F));
35
36 // Generate LoopInfo from it.
37 LoopInfo LI;
38 LI.analyze(DomTree: DT);
39
40 // Then compute BranchProbabilityInfo.
41 BranchProbabilityInfo BPI(*F, LI, nullptr, &DT, nullptr);
42
43 // Finally compute BFI.
44 OwnedBFI = std::make_unique<BlockFrequencyInfo>(args: *F, args&: BPI, args&: LI);
45 BFI = OwnedBFI.get();
46}
47
48bool OptimizationRemarkEmitter::invalidate(
49 Function &F, const PreservedAnalyses &PA,
50 FunctionAnalysisManager::Invalidator &Inv) {
51 if (OwnedBFI) {
52 OwnedBFI.reset();
53 BFI = nullptr;
54 }
55 // This analysis has no state and so can be trivially preserved but it needs
56 // a fresh view of BFI if it was constructed with one.
57 if (BFI && Inv.invalidate<BlockFrequencyAnalysis>(IR&: F, PA))
58 return true;
59
60 // Otherwise this analysis result remains valid.
61 return false;
62}
63
64std::optional<uint64_t>
65OptimizationRemarkEmitter::computeHotness(const Value *V) {
66 if (!BFI)
67 return std::nullopt;
68
69 return BFI->getBlockProfileCount(BB: cast<BasicBlock>(Val: V));
70}
71
72void OptimizationRemarkEmitter::computeHotness(
73 DiagnosticInfoIROptimization &OptDiag) {
74 const Value *V = OptDiag.getCodeRegion();
75 if (V)
76 OptDiag.setHotness(computeHotness(V));
77}
78
79void OptimizationRemarkEmitter::emit(
80 DiagnosticInfoOptimizationBase &OptDiagBase) {
81 auto &OptDiag = cast<DiagnosticInfoIROptimization>(Val&: OptDiagBase);
82 computeHotness(OptDiag);
83
84 // Only emit it if its hotness meets the threshold.
85 if (OptDiag.getHotness().value_or(u: 0) <
86 F->getContext().getDiagnosticsHotnessThreshold()) {
87 return;
88 }
89
90 F->getContext().diagnose(DI: OptDiag);
91}
92
93OptimizationRemarkEmitterWrapperPass::OptimizationRemarkEmitterWrapperPass()
94 : FunctionPass(ID) {
95 initializeOptimizationRemarkEmitterWrapperPassPass(
96 *PassRegistry::getPassRegistry());
97}
98
99bool OptimizationRemarkEmitterWrapperPass::runOnFunction(Function &Fn) {
100 BlockFrequencyInfo *BFI;
101
102 auto &Context = Fn.getContext();
103 if (Context.getDiagnosticsHotnessRequested()) {
104 BFI = &getAnalysis<LazyBlockFrequencyInfoPass>().getBFI();
105 // Get hotness threshold from PSI. This should only happen once.
106 if (Context.isDiagnosticsHotnessThresholdSetFromPSI()) {
107 if (ProfileSummaryInfo *PSI =
108 &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI())
109 Context.setDiagnosticsHotnessThreshold(
110 PSI->getOrCompHotCountThreshold());
111 }
112 } else
113 BFI = nullptr;
114
115 ORE = std::make_unique<OptimizationRemarkEmitter>(args: &Fn, args&: BFI);
116 return false;
117}
118
119void OptimizationRemarkEmitterWrapperPass::getAnalysisUsage(
120 AnalysisUsage &AU) const {
121 LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
122 AU.addRequired<ProfileSummaryInfoWrapperPass>();
123 AU.setPreservesAll();
124}
125
126AnalysisKey OptimizationRemarkEmitterAnalysis::Key;
127
128OptimizationRemarkEmitter
129OptimizationRemarkEmitterAnalysis::run(Function &F,
130 FunctionAnalysisManager &AM) {
131 BlockFrequencyInfo *BFI;
132 auto &Context = F.getContext();
133
134 if (Context.getDiagnosticsHotnessRequested()) {
135 BFI = &AM.getResult<BlockFrequencyAnalysis>(IR&: F);
136 // Get hotness threshold from PSI. This should only happen once.
137 if (Context.isDiagnosticsHotnessThresholdSetFromPSI()) {
138 auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(IR&: F);
139 if (ProfileSummaryInfo *PSI =
140 MAMProxy.getCachedResult<ProfileSummaryAnalysis>(IR&: *F.getParent()))
141 Context.setDiagnosticsHotnessThreshold(
142 PSI->getOrCompHotCountThreshold());
143 }
144 } else
145 BFI = nullptr;
146
147 return OptimizationRemarkEmitter(&F, BFI);
148}
149
150char OptimizationRemarkEmitterWrapperPass::ID = 0;
151static const char ore_name[] = "Optimization Remark Emitter";
152#define ORE_NAME "opt-remark-emitter"
153
154INITIALIZE_PASS_BEGIN(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,
155 false, true)
156INITIALIZE_PASS_DEPENDENCY(LazyBFIPass)
157INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
158INITIALIZE_PASS_END(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,
159 false, true)
160