xref: /freebsd/contrib/llvm-project/llvm/lib/Analysis/OptimizationRemarkEmitter.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===- OptimizationRemarkEmitter.cpp - Optimization Diagnostic --*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Optimization diagnostic interfaces.  It's packaged as an analysis pass so
100b57cec5SDimitry Andric // that by using this service passes become dependent on BFI as well.  BFI is
110b57cec5SDimitry Andric // used to compute the "hotness" of the diagnostic message.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
150b57cec5SDimitry Andric #include "llvm/Analysis/BranchProbabilityInfo.h"
160b57cec5SDimitry Andric #include "llvm/Analysis/LazyBlockFrequencyInfo.h"
170b57cec5SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
18e8d8bef9SDimitry Andric #include "llvm/Analysis/ProfileSummaryInfo.h"
190b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
200b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
210b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
22480093f4SDimitry Andric #include "llvm/InitializePasses.h"
23*bdd1243dSDimitry Andric #include <optional>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric 
OptimizationRemarkEmitter(const Function * F)270b57cec5SDimitry Andric OptimizationRemarkEmitter::OptimizationRemarkEmitter(const Function *F)
280b57cec5SDimitry Andric     : F(F), BFI(nullptr) {
290b57cec5SDimitry Andric   if (!F->getContext().getDiagnosticsHotnessRequested())
300b57cec5SDimitry Andric     return;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric   // First create a dominator tree.
330b57cec5SDimitry Andric   DominatorTree DT;
340b57cec5SDimitry Andric   DT.recalculate(*const_cast<Function *>(F));
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   // Generate LoopInfo from it.
370b57cec5SDimitry Andric   LoopInfo LI;
380b57cec5SDimitry Andric   LI.analyze(DT);
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   // Then compute BranchProbabilityInfo.
41e8d8bef9SDimitry Andric   BranchProbabilityInfo BPI(*F, LI, nullptr, &DT, nullptr);
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   // Finally compute BFI.
448bcb0991SDimitry Andric   OwnedBFI = std::make_unique<BlockFrequencyInfo>(*F, BPI, LI);
450b57cec5SDimitry Andric   BFI = OwnedBFI.get();
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric 
invalidate(Function & F,const PreservedAnalyses & PA,FunctionAnalysisManager::Invalidator & Inv)480b57cec5SDimitry Andric bool OptimizationRemarkEmitter::invalidate(
490b57cec5SDimitry Andric     Function &F, const PreservedAnalyses &PA,
500b57cec5SDimitry Andric     FunctionAnalysisManager::Invalidator &Inv) {
5181ad6265SDimitry Andric   if (OwnedBFI) {
525ffd83dbSDimitry Andric     OwnedBFI.reset();
535ffd83dbSDimitry Andric     BFI = nullptr;
545ffd83dbSDimitry Andric   }
550b57cec5SDimitry Andric   // This analysis has no state and so can be trivially preserved but it needs
560b57cec5SDimitry Andric   // a fresh view of BFI if it was constructed with one.
570b57cec5SDimitry Andric   if (BFI && Inv.invalidate<BlockFrequencyAnalysis>(F, PA))
580b57cec5SDimitry Andric     return true;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   // Otherwise this analysis result remains valid.
610b57cec5SDimitry Andric   return false;
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric 
64*bdd1243dSDimitry Andric std::optional<uint64_t>
computeHotness(const Value * V)65*bdd1243dSDimitry Andric OptimizationRemarkEmitter::computeHotness(const Value *V) {
660b57cec5SDimitry Andric   if (!BFI)
67*bdd1243dSDimitry Andric     return std::nullopt;
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   return BFI->getBlockProfileCount(cast<BasicBlock>(V));
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
computeHotness(DiagnosticInfoIROptimization & OptDiag)720b57cec5SDimitry Andric void OptimizationRemarkEmitter::computeHotness(
730b57cec5SDimitry Andric     DiagnosticInfoIROptimization &OptDiag) {
740b57cec5SDimitry Andric   const Value *V = OptDiag.getCodeRegion();
750b57cec5SDimitry Andric   if (V)
760b57cec5SDimitry Andric     OptDiag.setHotness(computeHotness(V));
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
emit(DiagnosticInfoOptimizationBase & OptDiagBase)790b57cec5SDimitry Andric void OptimizationRemarkEmitter::emit(
800b57cec5SDimitry Andric     DiagnosticInfoOptimizationBase &OptDiagBase) {
810b57cec5SDimitry Andric   auto &OptDiag = cast<DiagnosticInfoIROptimization>(OptDiagBase);
820b57cec5SDimitry Andric   computeHotness(OptDiag);
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   // Only emit it if its hotness meets the threshold.
8581ad6265SDimitry Andric   if (OptDiag.getHotness().value_or(0) <
860b57cec5SDimitry Andric       F->getContext().getDiagnosticsHotnessThreshold()) {
870b57cec5SDimitry Andric     return;
880b57cec5SDimitry Andric   }
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric   F->getContext().diagnose(OptDiag);
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric 
OptimizationRemarkEmitterWrapperPass()930b57cec5SDimitry Andric OptimizationRemarkEmitterWrapperPass::OptimizationRemarkEmitterWrapperPass()
940b57cec5SDimitry Andric     : FunctionPass(ID) {
950b57cec5SDimitry Andric   initializeOptimizationRemarkEmitterWrapperPassPass(
960b57cec5SDimitry Andric       *PassRegistry::getPassRegistry());
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric 
runOnFunction(Function & Fn)990b57cec5SDimitry Andric bool OptimizationRemarkEmitterWrapperPass::runOnFunction(Function &Fn) {
1000b57cec5SDimitry Andric   BlockFrequencyInfo *BFI;
1010b57cec5SDimitry Andric 
102e8d8bef9SDimitry Andric   auto &Context = Fn.getContext();
103e8d8bef9SDimitry Andric   if (Context.getDiagnosticsHotnessRequested()) {
1040b57cec5SDimitry Andric     BFI = &getAnalysis<LazyBlockFrequencyInfoPass>().getBFI();
105e8d8bef9SDimitry Andric     // Get hotness threshold from PSI. This should only happen once.
106e8d8bef9SDimitry Andric     if (Context.isDiagnosticsHotnessThresholdSetFromPSI()) {
107e8d8bef9SDimitry Andric       if (ProfileSummaryInfo *PSI =
108e8d8bef9SDimitry Andric               &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI())
109e8d8bef9SDimitry Andric         Context.setDiagnosticsHotnessThreshold(
110e8d8bef9SDimitry Andric             PSI->getOrCompHotCountThreshold());
111e8d8bef9SDimitry Andric     }
112e8d8bef9SDimitry Andric   } else
1130b57cec5SDimitry Andric     BFI = nullptr;
1140b57cec5SDimitry Andric 
1158bcb0991SDimitry Andric   ORE = std::make_unique<OptimizationRemarkEmitter>(&Fn, BFI);
1160b57cec5SDimitry Andric   return false;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const1190b57cec5SDimitry Andric void OptimizationRemarkEmitterWrapperPass::getAnalysisUsage(
1200b57cec5SDimitry Andric     AnalysisUsage &AU) const {
1210b57cec5SDimitry Andric   LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
122e8d8bef9SDimitry Andric   AU.addRequired<ProfileSummaryInfoWrapperPass>();
1230b57cec5SDimitry Andric   AU.setPreservesAll();
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric AnalysisKey OptimizationRemarkEmitterAnalysis::Key;
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric OptimizationRemarkEmitter
run(Function & F,FunctionAnalysisManager & AM)1290b57cec5SDimitry Andric OptimizationRemarkEmitterAnalysis::run(Function &F,
1300b57cec5SDimitry Andric                                        FunctionAnalysisManager &AM) {
1310b57cec5SDimitry Andric   BlockFrequencyInfo *BFI;
132e8d8bef9SDimitry Andric   auto &Context = F.getContext();
1330b57cec5SDimitry Andric 
134e8d8bef9SDimitry Andric   if (Context.getDiagnosticsHotnessRequested()) {
1350b57cec5SDimitry Andric     BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
136e8d8bef9SDimitry Andric     // Get hotness threshold from PSI. This should only happen once.
137e8d8bef9SDimitry Andric     if (Context.isDiagnosticsHotnessThresholdSetFromPSI()) {
138e8d8bef9SDimitry Andric       auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
139e8d8bef9SDimitry Andric       if (ProfileSummaryInfo *PSI =
140e8d8bef9SDimitry Andric               MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent()))
141e8d8bef9SDimitry Andric         Context.setDiagnosticsHotnessThreshold(
142e8d8bef9SDimitry Andric             PSI->getOrCompHotCountThreshold());
143e8d8bef9SDimitry Andric     }
144e8d8bef9SDimitry Andric   } else
1450b57cec5SDimitry Andric     BFI = nullptr;
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   return OptimizationRemarkEmitter(&F, BFI);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric char OptimizationRemarkEmitterWrapperPass::ID = 0;
1510b57cec5SDimitry Andric static const char ore_name[] = "Optimization Remark Emitter";
1520b57cec5SDimitry Andric #define ORE_NAME "opt-remark-emitter"
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,
1550b57cec5SDimitry Andric                       false, true)
1560b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LazyBFIPass)
157e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
1580b57cec5SDimitry Andric INITIALIZE_PASS_END(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,
1590b57cec5SDimitry Andric                     false, true)
160