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