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