xref: /freebsd/contrib/llvm-project/llvm/lib/Analysis/OptimizationRemarkEmitter.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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 
25 using namespace llvm;
26 
27 OptimizationRemarkEmitter::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(*const_cast<Function *>(F));
35 
36   // Generate LoopInfo from it.
37   LoopInfo LI;
38   LI.analyze(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>(*F, BPI, LI);
45   BFI = OwnedBFI.get();
46 }
47 
48 bool 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>(F, PA))
58     return true;
59 
60   // Otherwise this analysis result remains valid.
61   return false;
62 }
63 
64 std::optional<uint64_t>
65 OptimizationRemarkEmitter::computeHotness(const Value *V) {
66   if (!BFI)
67     return std::nullopt;
68 
69   return BFI->getBlockProfileCount(cast<BasicBlock>(V));
70 }
71 
72 void OptimizationRemarkEmitter::computeHotness(
73     DiagnosticInfoIROptimization &OptDiag) {
74   const Value *V = OptDiag.getCodeRegion();
75   if (V)
76     OptDiag.setHotness(computeHotness(V));
77 }
78 
79 void OptimizationRemarkEmitter::emit(
80     DiagnosticInfoOptimizationBase &OptDiagBase) {
81   auto &OptDiag = cast<DiagnosticInfoIROptimization>(OptDiagBase);
82   computeHotness(OptDiag);
83 
84   // Only emit it if its hotness meets the threshold.
85   if (OptDiag.getHotness().value_or(0) <
86       F->getContext().getDiagnosticsHotnessThreshold()) {
87     return;
88   }
89 
90   F->getContext().diagnose(OptDiag);
91 }
92 
93 OptimizationRemarkEmitterWrapperPass::OptimizationRemarkEmitterWrapperPass()
94     : FunctionPass(ID) {}
95 
96 bool OptimizationRemarkEmitterWrapperPass::runOnFunction(Function &Fn) {
97   BlockFrequencyInfo *BFI;
98 
99   auto &Context = Fn.getContext();
100   if (Context.getDiagnosticsHotnessRequested()) {
101     BFI = &getAnalysis<LazyBlockFrequencyInfoPass>().getBFI();
102     // Get hotness threshold from PSI. This should only happen once.
103     if (Context.isDiagnosticsHotnessThresholdSetFromPSI()) {
104       if (ProfileSummaryInfo *PSI =
105               &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI())
106         Context.setDiagnosticsHotnessThreshold(
107             PSI->getOrCompHotCountThreshold());
108     }
109   } else
110     BFI = nullptr;
111 
112   ORE = std::make_unique<OptimizationRemarkEmitter>(&Fn, BFI);
113   return false;
114 }
115 
116 void OptimizationRemarkEmitterWrapperPass::getAnalysisUsage(
117     AnalysisUsage &AU) const {
118   LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
119   AU.addRequired<ProfileSummaryInfoWrapperPass>();
120   AU.setPreservesAll();
121 }
122 
123 AnalysisKey OptimizationRemarkEmitterAnalysis::Key;
124 
125 OptimizationRemarkEmitter
126 OptimizationRemarkEmitterAnalysis::run(Function &F,
127                                        FunctionAnalysisManager &AM) {
128   BlockFrequencyInfo *BFI;
129   auto &Context = F.getContext();
130 
131   if (Context.getDiagnosticsHotnessRequested()) {
132     BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
133     // Get hotness threshold from PSI. This should only happen once.
134     if (Context.isDiagnosticsHotnessThresholdSetFromPSI()) {
135       auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
136       if (ProfileSummaryInfo *PSI =
137               MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent()))
138         Context.setDiagnosticsHotnessThreshold(
139             PSI->getOrCompHotCountThreshold());
140     }
141   } else
142     BFI = nullptr;
143 
144   return OptimizationRemarkEmitter(&F, BFI);
145 }
146 
147 char OptimizationRemarkEmitterWrapperPass::ID = 0;
148 static const char ore_name[] = "Optimization Remark Emitter";
149 #define ORE_NAME "opt-remark-emitter"
150 
151 INITIALIZE_PASS_BEGIN(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,
152                       false, true)
153 INITIALIZE_PASS_DEPENDENCY(LazyBFIPass)
154 INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
155 INITIALIZE_PASS_END(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,
156                     false, true)
157