15#include "llvm/ADT/Hashing.h"
16#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
17#include "llvm/Demangle/Demangle.h"
18#include "llvm/IR/DiagnosticInfo.h"
19#include "llvm/IR/DiagnosticPrinter.h"
20#include "llvm/IR/Function.h"
21#include "llvm/IR/Module.h"
22#include "llvm/Support/raw_ostream.h"
29class BackendDiagnosticHandlerImpl final :
public DiagnosticHandler {
31 BackendDiagnosticHandlerImpl(
const CodeGenOptions &CGOpts,
32 BackendDiagnosticConsumer *Consumer)
33 : CodeGenOpts(CGOpts), Consumer(Consumer) {}
35 bool handleDiagnostics(
const DiagnosticInfo &DI)
override {
36 Consumer->handleDiagnostics(DI);
40 bool isAnalysisRemarkEnabled(StringRef PassName)
const override {
41 return CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(PassName);
43 bool isMissedOptRemarkEnabled(StringRef PassName)
const override {
44 return CodeGenOpts.OptimizationRemarkMissed.patternMatches(PassName);
46 bool isPassedOptRemarkEnabled(StringRef PassName)
const override {
47 return CodeGenOpts.OptimizationRemark.patternMatches(PassName);
50 bool isAnyRemarkEnabled()
const override {
51 return CodeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() ||
52 CodeGenOpts.OptimizationRemarkMissed.hasValidPattern() ||
53 CodeGenOpts.OptimizationRemark.hasValidPattern();
57 const CodeGenOptions &CodeGenOpts;
58 BackendDiagnosticConsumer *Consumer;
63FullSourceLoc ConvertBackendLocation(
const llvm::SMDiagnostic &D,
68 const llvm::SourceMgr &LSM = *D.getSourceMgr();
72 const MemoryBuffer *LBuf =
73 LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
77 std::unique_ptr<llvm::MemoryBuffer> CBuf =
78 llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(),
79 LBuf->getBufferIdentifier());
84 unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
92#define ComputeDiagID(Severity, GroupName, DiagID) \
95 case llvm::DS_Error: \
96 DiagID = diag::err_fe_##GroupName; \
98 case llvm::DS_Warning: \
99 DiagID = diag::warn_fe_##GroupName; \
101 case llvm::DS_Remark: \
102 llvm_unreachable("'remark' severity not expected"); \
104 case llvm::DS_Note: \
105 DiagID = diag::note_fe_##GroupName; \
110#define ComputeDiagRemarkID(Severity, GroupName, DiagID) \
112 switch (Severity) { \
113 case llvm::DS_Error: \
114 DiagID = diag::err_fe_##GroupName; \
116 case llvm::DS_Warning: \
117 DiagID = diag::warn_fe_##GroupName; \
119 case llvm::DS_Remark: \
120 DiagID = diag::remark_fe_##GroupName; \
122 case llvm::DS_Note: \
123 DiagID = diag::note_fe_##GroupName; \
128std::unique_ptr<llvm::DiagnosticHandler>
130 return std::make_unique<BackendDiagnosticHandlerImpl>(CodeGenOpts,
this);
137 ManglingFullSourceLocs.push_back(std::make_pair(NameHash, Loc));
140std::optional<FullSourceLoc>
143 for (
const auto &Pair : ManglingFullSourceLocs) {
144 if (Pair.first == Hash)
151 const llvm::DiagnosticInfoWithLocationBase &D,
bool &BadDebugInfo,
152 StringRef &Filename,
unsigned &
Line,
unsigned &
Column)
const {
157 if (D.isLocationAvailable()) {
160 auto FE =
FileMgr.getOptionalFileRef(Filename);
162 FE =
FileMgr.getOptionalFileRef(D.getAbsolutePath());
181 if (DILoc.
isInvalid() && D.isLocationAvailable())
186 Diags.Report(Loc, diag::note_fe_backend_invalid_loc)
192void BackendDiagnosticConsumer::SrcMgrDiagHandler(
193 const llvm::DiagnosticInfoSrcMgr &DI) {
194 const llvm::SMDiagnostic &D = DI.getSMDiag();
197 if (DI.isInlineAsmDiag())
205 D.print(
nullptr, llvm::errs());
214 StringRef Message = D.getMessage();
215 (void)Message.consume_front(
"error: ");
219 if (D.getLoc() != SMLoc())
220 Loc = ConvertBackendLocation(D, *SM);
225 if (DI.isInlineAsmDiag()) {
231 if (D.getLoc().isValid()) {
235 for (
const std::pair<unsigned, unsigned> &Range : D.getRanges()) {
236 unsigned Column = D.getColumnNo();
248 Diags.Report(Loc, DiagID).AddString(Message);
251bool BackendDiagnosticConsumer::InlineAsmDiagHandler(
252 const llvm::DiagnosticInfoInlineAsm &D) {
255 std::string
Message = D.getMsgStr().str();
260 SourceLocation LocCookie =
263 Diags.Report(LocCookie, DiagID).AddString(Message);
270 Diags.Report(Loc, DiagID).AddString(Message);
276bool BackendDiagnosticConsumer::StackSizeDiagHandler(
277 const llvm::DiagnosticInfoStackSize &D) {
278 if (D.getSeverity() != llvm::DS_Warning)
287 Diags.Report(*Loc, diag::warn_fe_frame_larger_than)
288 << D.getStackSize() << D.getStackLimit()
289 << llvm::demangle(D.getFunction().getName());
293bool BackendDiagnosticConsumer::ResourceLimitDiagHandler(
294 const llvm::DiagnosticInfoResourceLimit &D) {
298 unsigned DiagID = diag::err_fe_backend_resource_limit;
299 ComputeDiagID(D.getSeverity(), backend_resource_limit, DiagID);
301 Diags.Report(*Loc, DiagID)
302 << D.getResourceName() << D.getResourceSize() << D.getResourceLimit()
303 << llvm::demangle(D.getFunction().getName());
307void BackendDiagnosticConsumer::UnsupportedDiagHandler(
308 const llvm::DiagnosticInfoUnsupported &D) {
310 assert(D.getSeverity() == llvm::DS_Error ||
311 D.getSeverity() == llvm::DS_Warning);
315 bool BadDebugInfo =
false;
318 raw_string_ostream MsgStream(Msg);
324 MsgStream << D.getMessage();
326 DiagnosticPrinterRawOStream DP(MsgStream);
330 auto DiagType = D.getSeverity() == llvm::DS_Error
331 ? diag::err_fe_backend_unsupported
332 : diag::warn_fe_backend_unsupported;
333 Diags.Report(Loc, DiagType) << Msg;
340 Diags.Report(Loc, diag::note_fe_backend_invalid_loc)
344void BackendDiagnosticConsumer::UnsupportedTargetIntrinsicDiagHandler(
345 const llvm::DiagnosticInfoUnsupportedTargetIntrinsic &D) {
346 assert(D.getSeverity() == llvm::DS_Error &&
347 "unsupported target intrinsic diagnostic should be an error");
351 bool BadDebugInfo =
false;
354 raw_string_ostream MsgStream(Msg);
360 MsgStream << D.getMessage();
362 DiagnosticPrinterRawOStream DP(MsgStream);
366 Diags.Report(Loc, diag::err_fe_backend_unsupported) << Msg;
373 Diags.Report(Loc, diag::note_fe_backend_invalid_loc)
378void BackendDiagnosticConsumer::EmitOptimizationMessage(
379 const llvm::DiagnosticInfoOptimizationBase &D,
unsigned DiagID) {
381 assert(D.getSeverity() == llvm::DS_Remark ||
382 D.getSeverity() == llvm::DS_Warning);
386 bool BadDebugInfo =
false;
389 raw_string_ostream MsgStream(Msg);
395 MsgStream << D.getMsg();
397 DiagnosticPrinterRawOStream DP(MsgStream);
402 MsgStream <<
" (hotness: " << *D.getHotness() <<
")";
404 Diags.Report(Loc, DiagID) << AddFlagValue(D.getPassName()) << Msg;
411 Diags.Report(Loc, diag::note_fe_backend_invalid_loc)
415void BackendDiagnosticConsumer::OptimizationRemarkHandler(
416 const llvm::DiagnosticInfoOptimizationBase &D) {
418 if (D.isVerbose() && !D.getHotness())
424 if (CodeGenOpts.OptimizationRemark.patternMatches(D.getPassName()))
425 EmitOptimizationMessage(D, diag::remark_fe_backend_optimization_remark);
426 }
else if (D.isMissed()) {
430 if (CodeGenOpts.OptimizationRemarkMissed.patternMatches(D.getPassName()))
431 EmitOptimizationMessage(
432 D, diag::remark_fe_backend_optimization_remark_missed);
434 assert(D.isAnalysis() &&
"Unknown remark type");
436 bool ShouldAlwaysPrint =
false;
437 if (
auto *ORA = dyn_cast<llvm::OptimizationRemarkAnalysis>(&D))
438 ShouldAlwaysPrint = ORA->shouldAlwaysPrint();
440 if (ShouldAlwaysPrint ||
441 CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(D.getPassName()))
442 EmitOptimizationMessage(
443 D, diag::remark_fe_backend_optimization_remark_analysis);
447void BackendDiagnosticConsumer::OptimizationRemarkHandler(
448 const llvm::OptimizationRemarkAnalysisFPCommute &D) {
453 if (D.shouldAlwaysPrint() ||
454 CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(D.getPassName()))
455 EmitOptimizationMessage(
456 D, diag::remark_fe_backend_optimization_remark_analysis_fpcommute);
459void BackendDiagnosticConsumer::OptimizationRemarkHandler(
460 const llvm::OptimizationRemarkAnalysisAliasing &D) {
465 if (D.shouldAlwaysPrint() ||
466 CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(D.getPassName()))
467 EmitOptimizationMessage(
468 D, diag::remark_fe_backend_optimization_remark_analysis_aliasing);
471void BackendDiagnosticConsumer::OptimizationFailureHandler(
472 const llvm::DiagnosticInfoOptimizationFailure &D) {
473 EmitOptimizationMessage(D, diag::warn_fe_backend_optimization_failure);
476void BackendDiagnosticConsumer::DontCallDiagHandler(
477 const DiagnosticInfoDontCall &D) {
478 SourceLocation LocCookie =
486 Diags.Report(LocCookie, D.getSeverity() == DiagnosticSeverity::DS_Error
487 ? diag::err_fe_backend_error_attr
488 : diag::warn_fe_backend_warning_attr)
489 << llvm::demangle(D.getFunctionName()) << D.getNote();
491 if (!CodeGenOpts.ShowInliningChain)
494 auto EmitNote = [&](SourceLocation Loc, StringRef FuncName,
bool IsFirst) {
498 IsFirst ? diag::note_fe_backend_in : diag::note_fe_backend_inlined;
499 Diags.Report(Loc, DiagID) << llvm::demangle(FuncName.str());
503 if (!D.getDebugInlineChain().empty()) {
504 SourceManager &SrcMgr = *SM;
506 for (
const auto &[I, Info] : llvm::enumerate(D.getDebugInlineChain())) {
511 Info.Column ? Info.Column : 1);
512 EmitNote(Loc, Info.FuncName, I == 0);
518 auto InliningDecisions = D.getInliningDecisions();
519 if (InliningDecisions.empty())
522 for (
const auto &[I, Entry] : llvm::enumerate(InliningDecisions)) {
525 EmitNote(Loc, Entry.first, I == 0);
530 Diags.Report(LocCookie, diag::note_fe_backend_inlining_debug_info);
533void BackendDiagnosticConsumer::MisExpectDiagHandler(
534 const llvm::DiagnosticInfoMisExpect &D) {
537 bool BadDebugInfo =
false;
541 Diags.Report(Loc, diag::warn_profile_data_misexpect) << D.getMsg().str();
548 Diags.Report(Loc, diag::note_fe_backend_invalid_loc)
553 unsigned DiagID = diag::err_fe_inline_asm;
554 llvm::DiagnosticSeverity Severity = DI.getSeverity();
556 switch (DI.getKind()) {
557 case llvm::DK_InlineAsm:
562 case llvm::DK_SrcMgr:
565 case llvm::DK_StackSize:
570 case llvm::DK_ResourceLimit:
578 case llvm::DK_OptimizationRemark:
583 case llvm::DK_OptimizationRemarkMissed:
588 case llvm::DK_OptimizationRemarkAnalysis:
593 case llvm::DK_OptimizationRemarkAnalysisFPCommute:
598 case llvm::DK_OptimizationRemarkAnalysisAliasing:
603 case llvm::DK_MachineOptimizationRemark:
608 case llvm::DK_MachineOptimizationRemarkMissed:
613 case llvm::DK_MachineOptimizationRemarkAnalysis:
618 case llvm::DK_OptimizationFailure:
623 case llvm::DK_Unsupported:
626 case llvm::DK_UnsupportedTargetIntrinsic:
627 UnsupportedTargetIntrinsicDiagHandler(
630 case llvm::DK_DontCall:
633 case llvm::DK_MisExpect:
641 std::string MsgStorage;
643 raw_string_ostream Stream(MsgStorage);
644 DiagnosticPrinterRawOStream DP(Stream);
648 if (DI.getKind() == DK_Linker) {
649 assert(CurLinkModule &&
"CurLinkModule must be set for linker diagnostics");
650 Diags.Report(DiagID) << CurLinkModule->getModuleIdentifier() << MsgStorage;
656 Diags.Report(Loc, DiagID).AddString(MsgStorage);
660#undef ComputeDiagRemarkID
#define ComputeDiagID(Severity, GroupName, DiagID)
#define ComputeDiagRemarkID(Severity, GroupName, DiagID)
Defines the Diagnostic-related interfaces.
Defines the clang::FileManager interface and associated types.
Defines the SourceManager interface.
void addFunctionSourceLocation(StringRef MangledName, FullSourceLoc Loc)
Record the source location of the function with the given mangled name, used to approximate a locatio...
std::unique_ptr< llvm::DiagnosticHandler > createDiagnosticHandler()
Create an llvm::DiagnosticHandler that forwards diagnostics to this consumer.
std::optional< FullSourceLoc > getFunctionSourceLocation(const llvm::Function &F) const
void handleDiagnostics(const llvm::DiagnosticInfo &DI)
This is invoked when the backend needs to report something to the user.
const FullSourceLoc getBestLocationFromDebugLoc(const llvm::DiagnosticInfoWithLocationBase &D, bool &BadDebugInfo, StringRef &Filename, unsigned &Line, unsigned &Column) const
Get the best possible source location to represent a diagnostic that may have associated debug info.
A little helper class used to produce diagnostics.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Implements support for file system lookup, file system caching, and directory search management.
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true, bool IsText=true)
Get a FileEntryRef if it exists, without doing anything on error.
A SourceLocation and its associated SourceManager.
Encodes a location in the source.
static SourceLocation getFromRawEncoding(UIntTy Encoding)
Turn a raw encoding of a SourceLocation object into a real SourceLocation.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
FileID createFileID(FileEntryRef SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID=0, SourceLocation::UIntTy LoadedOffset=0)
Create a new FileID that represents the specified file being #included from the specified IncludePosi...
FileManager & getFileManager() const
SourceLocation translateFileLineCol(const FileEntry *SourceFile, unsigned Line, unsigned Col) const
Get the source location for the given file:line:col triplet.
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
A trivial tuple used to represent a source range.
void AddString(StringRef V) const
Top level wrappers for InstallAPI frontend operations.
U cast(CodeGen::Address addr)
Diagnostic wrappers for TextAPI types for error reporting.
hash_code hash_value(const clang::dependencies::ModuleID &ID)