157 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Optimization diagnostic interfaces. It's packaged as an analysis pass so10// that by using this service passes become dependent on BFI as well. BFI is11// 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 25using namespace llvm;26 27OptimizationRemarkEmitter::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 48bool 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 needs56 // 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 64std::optional<uint64_t>65OptimizationRemarkEmitter::computeHotness(const Value *V) {66 if (!BFI)67 return std::nullopt;68 69 return BFI->getBlockProfileCount(cast<BasicBlock>(V));70}71 72void OptimizationRemarkEmitter::computeHotness(73 DiagnosticInfoIROptimization &OptDiag) {74 const Value *V = OptDiag.getCodeRegion();75 if (V)76 OptDiag.setHotness(computeHotness(V));77}78 79void 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 93OptimizationRemarkEmitterWrapperPass::OptimizationRemarkEmitterWrapperPass()94 : FunctionPass(ID) {}95 96bool 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 } else110 BFI = nullptr;111 112 ORE = std::make_unique<OptimizationRemarkEmitter>(&Fn, BFI);113 return false;114}115 116void OptimizationRemarkEmitterWrapperPass::getAnalysisUsage(117 AnalysisUsage &AU) const {118 LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);119 AU.addRequired<ProfileSummaryInfoWrapperPass>();120 AU.setPreservesAll();121}122 123AnalysisKey OptimizationRemarkEmitterAnalysis::Key;124 125OptimizationRemarkEmitter126OptimizationRemarkEmitterAnalysis::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 } else142 BFI = nullptr;143 144 return OptimizationRemarkEmitter(&F, BFI);145}146 147char OptimizationRemarkEmitterWrapperPass::ID = 0;148static const char ore_name[] = "Optimization Remark Emitter";149#define ORE_NAME "opt-remark-emitter"150 151INITIALIZE_PASS_BEGIN(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,152 false, true)153INITIALIZE_PASS_DEPENDENCY(LazyBFIPass)154INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)155INITIALIZE_PASS_END(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,156 false, true)157