232 lines
9.0 KiB
C
232 lines
9.0 KiB
C
|
///===- MachineOptimizationRemarkEmitter.h - Opt Diagnostics -*- C++ -*----===//
|
||
|
///
|
||
|
/// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||
|
/// See https://llvm.org/LICENSE.txt for license information.
|
||
|
/// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||
|
///
|
||
|
///===---------------------------------------------------------------------===//
|
||
|
/// \file
|
||
|
/// Optimization diagnostic interfaces for machine passes. It's packaged as an
|
||
|
/// analysis pass so that by using this service passes become dependent on MBFI
|
||
|
/// as well. MBFI is used to compute the "hotness" of the diagnostic message.
|
||
|
///
|
||
|
///===---------------------------------------------------------------------===//
|
||
|
|
||
|
#ifndef LLVM_CODEGEN_MACHINEOPTIMIZATIONREMARKEMITTER_H
|
||
|
#define LLVM_CODEGEN_MACHINEOPTIMIZATIONREMARKEMITTER_H
|
||
|
|
||
|
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
|
||
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||
|
|
||
|
namespace llvm {
|
||
|
class MachineBasicBlock;
|
||
|
class MachineBlockFrequencyInfo;
|
||
|
class MachineInstr;
|
||
|
|
||
|
/// Common features for diagnostics dealing with optimization remarks
|
||
|
/// that are used by machine passes.
|
||
|
class DiagnosticInfoMIROptimization : public DiagnosticInfoOptimizationBase {
|
||
|
public:
|
||
|
DiagnosticInfoMIROptimization(enum DiagnosticKind Kind, const char *PassName,
|
||
|
StringRef RemarkName,
|
||
|
const DiagnosticLocation &Loc,
|
||
|
const MachineBasicBlock *MBB)
|
||
|
: DiagnosticInfoOptimizationBase(Kind, DS_Remark, PassName, RemarkName,
|
||
|
MBB->getParent()->getFunction(), Loc),
|
||
|
MBB(MBB) {}
|
||
|
|
||
|
/// MI-specific kinds of diagnostic Arguments.
|
||
|
struct MachineArgument : public DiagnosticInfoOptimizationBase::Argument {
|
||
|
/// Print an entire MachineInstr.
|
||
|
MachineArgument(StringRef Key, const MachineInstr &MI);
|
||
|
};
|
||
|
|
||
|
static bool classof(const DiagnosticInfo *DI) {
|
||
|
return DI->getKind() >= DK_FirstMachineRemark &&
|
||
|
DI->getKind() <= DK_LastMachineRemark;
|
||
|
}
|
||
|
|
||
|
const MachineBasicBlock *getBlock() const { return MBB; }
|
||
|
|
||
|
private:
|
||
|
const MachineBasicBlock *MBB;
|
||
|
};
|
||
|
|
||
|
/// Diagnostic information for applied optimization remarks.
|
||
|
class MachineOptimizationRemark : public DiagnosticInfoMIROptimization {
|
||
|
public:
|
||
|
/// \p PassName is the name of the pass emitting this diagnostic. If this name
|
||
|
/// matches the regular expression given in -Rpass=, then the diagnostic will
|
||
|
/// be emitted. \p RemarkName is a textual identifier for the remark. \p
|
||
|
/// Loc is the debug location and \p MBB is the block that the optimization
|
||
|
/// operates in.
|
||
|
MachineOptimizationRemark(const char *PassName, StringRef RemarkName,
|
||
|
const DiagnosticLocation &Loc,
|
||
|
const MachineBasicBlock *MBB)
|
||
|
: DiagnosticInfoMIROptimization(DK_MachineOptimizationRemark, PassName,
|
||
|
RemarkName, Loc, MBB) {}
|
||
|
|
||
|
static bool classof(const DiagnosticInfo *DI) {
|
||
|
return DI->getKind() == DK_MachineOptimizationRemark;
|
||
|
}
|
||
|
|
||
|
/// \see DiagnosticInfoOptimizationBase::isEnabled.
|
||
|
bool isEnabled() const override {
|
||
|
const Function &Fn = getFunction();
|
||
|
LLVMContext &Ctx = Fn.getContext();
|
||
|
return Ctx.getDiagHandlerPtr()->isPassedOptRemarkEnabled(getPassName());
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// Diagnostic information for missed-optimization remarks.
|
||
|
class MachineOptimizationRemarkMissed : public DiagnosticInfoMIROptimization {
|
||
|
public:
|
||
|
/// \p PassName is the name of the pass emitting this diagnostic. If this name
|
||
|
/// matches the regular expression given in -Rpass-missed=, then the
|
||
|
/// diagnostic will be emitted. \p RemarkName is a textual identifier for the
|
||
|
/// remark. \p Loc is the debug location and \p MBB is the block that the
|
||
|
/// optimization operates in.
|
||
|
MachineOptimizationRemarkMissed(const char *PassName, StringRef RemarkName,
|
||
|
const DiagnosticLocation &Loc,
|
||
|
const MachineBasicBlock *MBB)
|
||
|
: DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkMissed,
|
||
|
PassName, RemarkName, Loc, MBB) {}
|
||
|
|
||
|
static bool classof(const DiagnosticInfo *DI) {
|
||
|
return DI->getKind() == DK_MachineOptimizationRemarkMissed;
|
||
|
}
|
||
|
|
||
|
/// \see DiagnosticInfoOptimizationBase::isEnabled.
|
||
|
bool isEnabled() const override {
|
||
|
const Function &Fn = getFunction();
|
||
|
LLVMContext &Ctx = Fn.getContext();
|
||
|
return Ctx.getDiagHandlerPtr()->isMissedOptRemarkEnabled(getPassName());
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// Diagnostic information for optimization analysis remarks.
|
||
|
class MachineOptimizationRemarkAnalysis : public DiagnosticInfoMIROptimization {
|
||
|
public:
|
||
|
/// \p PassName is the name of the pass emitting this diagnostic. If this name
|
||
|
/// matches the regular expression given in -Rpass-analysis=, then the
|
||
|
/// diagnostic will be emitted. \p RemarkName is a textual identifier for the
|
||
|
/// remark. \p Loc is the debug location and \p MBB is the block that the
|
||
|
/// optimization operates in.
|
||
|
MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName,
|
||
|
const DiagnosticLocation &Loc,
|
||
|
const MachineBasicBlock *MBB)
|
||
|
: DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis,
|
||
|
PassName, RemarkName, Loc, MBB) {}
|
||
|
|
||
|
static bool classof(const DiagnosticInfo *DI) {
|
||
|
return DI->getKind() == DK_MachineOptimizationRemarkAnalysis;
|
||
|
}
|
||
|
|
||
|
/// \see DiagnosticInfoOptimizationBase::isEnabled.
|
||
|
bool isEnabled() const override {
|
||
|
const Function &Fn = getFunction();
|
||
|
LLVMContext &Ctx = Fn.getContext();
|
||
|
return Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(getPassName());
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// Extend llvm::ore:: with MI-specific helper names.
|
||
|
namespace ore {
|
||
|
using MNV = DiagnosticInfoMIROptimization::MachineArgument;
|
||
|
}
|
||
|
|
||
|
/// The optimization diagnostic interface.
|
||
|
///
|
||
|
/// It allows reporting when optimizations are performed and when they are not
|
||
|
/// along with the reasons for it. Hotness information of the corresponding
|
||
|
/// code region can be included in the remark if DiagnosticsHotnessRequested is
|
||
|
/// enabled in the LLVM context.
|
||
|
class MachineOptimizationRemarkEmitter {
|
||
|
public:
|
||
|
MachineOptimizationRemarkEmitter(MachineFunction &MF,
|
||
|
MachineBlockFrequencyInfo *MBFI)
|
||
|
: MF(MF), MBFI(MBFI) {}
|
||
|
|
||
|
/// Emit an optimization remark.
|
||
|
void emit(DiagnosticInfoOptimizationBase &OptDiag);
|
||
|
|
||
|
/// Whether we allow for extra compile-time budget to perform more
|
||
|
/// analysis to be more informative.
|
||
|
///
|
||
|
/// This is useful to enable additional missed optimizations to be reported
|
||
|
/// that are normally too noisy. In this mode, we can use the extra analysis
|
||
|
/// (1) to filter trivial false positives or (2) to provide more context so
|
||
|
/// that non-trivial false positives can be quickly detected by the user.
|
||
|
bool allowExtraAnalysis(StringRef PassName) const {
|
||
|
return (
|
||
|
MF.getFunction().getContext().getLLVMRemarkStreamer() ||
|
||
|
MF.getFunction().getContext().getDiagHandlerPtr()->isAnyRemarkEnabled(
|
||
|
PassName));
|
||
|
}
|
||
|
|
||
|
/// Take a lambda that returns a remark which will be emitted. Second
|
||
|
/// argument is only used to restrict this to functions.
|
||
|
template <typename T>
|
||
|
void emit(T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) {
|
||
|
// Avoid building the remark unless we know there are at least *some*
|
||
|
// remarks enabled. We can't currently check whether remarks are requested
|
||
|
// for the calling pass since that requires actually building the remark.
|
||
|
|
||
|
if (MF.getFunction().getContext().getLLVMRemarkStreamer() ||
|
||
|
MF.getFunction()
|
||
|
.getContext()
|
||
|
.getDiagHandlerPtr()
|
||
|
->isAnyRemarkEnabled()) {
|
||
|
auto R = RemarkBuilder();
|
||
|
emit((DiagnosticInfoOptimizationBase &)R);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MachineBlockFrequencyInfo *getBFI() {
|
||
|
return MBFI;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
MachineFunction &MF;
|
||
|
|
||
|
/// MBFI is only set if hotness is requested.
|
||
|
MachineBlockFrequencyInfo *MBFI;
|
||
|
|
||
|
/// Compute hotness from IR value (currently assumed to be a block) if PGO is
|
||
|
/// available.
|
||
|
Optional<uint64_t> computeHotness(const MachineBasicBlock &MBB);
|
||
|
|
||
|
/// Similar but use value from \p OptDiag and update hotness there.
|
||
|
void computeHotness(DiagnosticInfoMIROptimization &Remark);
|
||
|
|
||
|
/// Only allow verbose messages if we know we're filtering by hotness
|
||
|
/// (BFI is only set in this case).
|
||
|
bool shouldEmitVerbose() { return MBFI != nullptr; }
|
||
|
};
|
||
|
|
||
|
/// The analysis pass
|
||
|
///
|
||
|
/// Note that this pass shouldn't generally be marked as preserved by other
|
||
|
/// passes. It's holding onto BFI, so if the pass does not preserve BFI, BFI
|
||
|
/// could be freed.
|
||
|
class MachineOptimizationRemarkEmitterPass : public MachineFunctionPass {
|
||
|
std::unique_ptr<MachineOptimizationRemarkEmitter> ORE;
|
||
|
|
||
|
public:
|
||
|
MachineOptimizationRemarkEmitterPass();
|
||
|
|
||
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
||
|
|
||
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||
|
|
||
|
MachineOptimizationRemarkEmitter &getORE() {
|
||
|
assert(ORE && "pass not run yet");
|
||
|
return *ORE;
|
||
|
}
|
||
|
|
||
|
static char ID;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#endif
|