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