//===- llvm/IR/DiagnosticInfo.h - Diagnostic Declaration --------*- 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 // //===----------------------------------------------------------------------===// // // This file declares the different classes involved in low level diagnostics. // // Diagnostics reporting is still done as part of the LLVMContext. //===----------------------------------------------------------------------===// #ifndef LLVM_IR_DIAGNOSTICINFO_H #define LLVM_IR_DIAGNOSTICINFO_H #include "llvm-c/Types.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DebugLoc.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TypeSize.h" #include #include #include #include #include #include namespace llvm { // Forward declarations. class DiagnosticPrinter; class DIFile; class DISubprogram; class CallInst; class Function; class Instruction; class InstructionCost; class Module; class Type; class Value; /// Defines the different supported severity of a diagnostic. enum DiagnosticSeverity : char { DS_Error, DS_Warning, DS_Remark, // A note attaches additional information to one of the previous diagnostic // types. DS_Note }; /// Defines the different supported kind of a diagnostic. /// This enum should be extended with a new ID for each added concrete subclass. enum DiagnosticKind { DK_InlineAsm, DK_ResourceLimit, DK_StackSize, DK_Linker, DK_Lowering, DK_DebugMetadataVersion, DK_DebugMetadataInvalid, DK_ISelFallback, DK_SampleProfile, DK_OptimizationRemark, DK_OptimizationRemarkMissed, DK_OptimizationRemarkAnalysis, DK_OptimizationRemarkAnalysisFPCommute, DK_OptimizationRemarkAnalysisAliasing, DK_OptimizationFailure, DK_FirstRemark = DK_OptimizationRemark, DK_LastRemark = DK_OptimizationFailure, DK_MachineOptimizationRemark, DK_MachineOptimizationRemarkMissed, DK_MachineOptimizationRemarkAnalysis, DK_FirstMachineRemark = DK_MachineOptimizationRemark, DK_LastMachineRemark = DK_MachineOptimizationRemarkAnalysis, DK_MIRParser, DK_PGOProfile, DK_Unsupported, DK_SrcMgr, DK_DontCall, DK_MisExpect, DK_FirstPluginKind // Must be last value to work with // getNextAvailablePluginDiagnosticKind }; /// Get the next available kind ID for a plugin diagnostic. /// Each time this function is called, it returns a different number. /// Therefore, a plugin that wants to "identify" its own classes /// with a dynamic identifier, just have to use this method to get a new ID /// and assign it to each of its classes. /// The returned ID will be greater than or equal to DK_FirstPluginKind. /// Thus, the plugin identifiers will not conflict with the /// DiagnosticKind values. int getNextAvailablePluginDiagnosticKind(); /// This is the base abstract class for diagnostic reporting in /// the backend. /// The print method must be overloaded by the subclasses to print a /// user-friendly message in the client of the backend (let us call it a /// frontend). class DiagnosticInfo { private: /// Kind defines the kind of report this is about. const /* DiagnosticKind */ int Kind; /// Severity gives the severity of the diagnostic. const DiagnosticSeverity Severity; virtual void anchor(); public: DiagnosticInfo(/* DiagnosticKind */ int Kind, DiagnosticSeverity Severity) : Kind(Kind), Severity(Severity) {} virtual ~DiagnosticInfo() = default; /* DiagnosticKind */ int getKind() const { return Kind; } DiagnosticSeverity getSeverity() const { return Severity; } /// Print using the given \p DP a user-friendly message. /// This is the default message that will be printed to the user. /// It is used when the frontend does not directly take advantage /// of the information contained in fields of the subclasses. /// The printed message must not end with '.' nor start with a severity /// keyword. virtual void print(DiagnosticPrinter &DP) const = 0; }; using DiagnosticHandlerFunction = std::function; /// Diagnostic information for inline asm reporting. /// This is basically a message and an optional location. class DiagnosticInfoInlineAsm : public DiagnosticInfo { private: /// Optional line information. 0 if not set. uint64_t LocCookie = 0; /// Message to be reported. const Twine &MsgStr; /// Optional origin of the problem. const Instruction *Instr = nullptr; public: /// \p MsgStr is the message to be reported to the frontend. /// This class does not copy \p MsgStr, therefore the reference must be valid /// for the whole life time of the Diagnostic. DiagnosticInfoInlineAsm(const Twine &MsgStr, DiagnosticSeverity Severity = DS_Error) : DiagnosticInfo(DK_InlineAsm, Severity), MsgStr(MsgStr) {} /// \p LocCookie if non-zero gives the line number for this report. /// \p MsgStr gives the message. /// This class does not copy \p MsgStr, therefore the reference must be valid /// for the whole life time of the Diagnostic. DiagnosticInfoInlineAsm(uint64_t LocCookie, const Twine &MsgStr, DiagnosticSeverity Severity = DS_Error) : DiagnosticInfo(DK_InlineAsm, Severity), LocCookie(LocCookie), MsgStr(MsgStr) {} /// \p Instr gives the original instruction that triggered the diagnostic. /// \p MsgStr gives the message. /// This class does not copy \p MsgStr, therefore the reference must be valid /// for the whole life time of the Diagnostic. /// Same for \p I. DiagnosticInfoInlineAsm(const Instruction &I, const Twine &MsgStr, DiagnosticSeverity Severity = DS_Error); uint64_t getLocCookie() const { return LocCookie; } const Twine &getMsgStr() const { return MsgStr; } const Instruction *getInstruction() const { return Instr; } /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_InlineAsm; } }; /// Diagnostic information for debug metadata version reporting. /// This is basically a module and a version. class DiagnosticInfoDebugMetadataVersion : public DiagnosticInfo { private: /// The module that is concerned by this debug metadata version diagnostic. const Module &M; /// The actual metadata version. unsigned MetadataVersion; public: /// \p The module that is concerned by this debug metadata version diagnostic. /// \p The actual metadata version. DiagnosticInfoDebugMetadataVersion(const Module &M, unsigned MetadataVersion, DiagnosticSeverity Severity = DS_Warning) : DiagnosticInfo(DK_DebugMetadataVersion, Severity), M(M), MetadataVersion(MetadataVersion) {} const Module &getModule() const { return M; } unsigned getMetadataVersion() const { return MetadataVersion; } /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_DebugMetadataVersion; } }; /// Diagnostic information for stripping invalid debug metadata. class DiagnosticInfoIgnoringInvalidDebugMetadata : public DiagnosticInfo { private: /// The module that is concerned by this debug metadata version diagnostic. const Module &M; public: /// \p The module that is concerned by this debug metadata version diagnostic. DiagnosticInfoIgnoringInvalidDebugMetadata( const Module &M, DiagnosticSeverity Severity = DS_Warning) : DiagnosticInfo(DK_DebugMetadataVersion, Severity), M(M) {} const Module &getModule() const { return M; } /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_DebugMetadataInvalid; } }; /// Diagnostic information for the sample profiler. class DiagnosticInfoSampleProfile : public DiagnosticInfo { public: DiagnosticInfoSampleProfile(StringRef FileName, unsigned LineNum, const Twine &Msg, DiagnosticSeverity Severity = DS_Error) : DiagnosticInfo(DK_SampleProfile, Severity), FileName(FileName), LineNum(LineNum), Msg(Msg) {} DiagnosticInfoSampleProfile(StringRef FileName, const Twine &Msg, DiagnosticSeverity Severity = DS_Error) : DiagnosticInfo(DK_SampleProfile, Severity), FileName(FileName), Msg(Msg) {} DiagnosticInfoSampleProfile(const Twine &Msg, DiagnosticSeverity Severity = DS_Error) : DiagnosticInfo(DK_SampleProfile, Severity), Msg(Msg) {} /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_SampleProfile; } StringRef getFileName() const { return FileName; } unsigned getLineNum() const { return LineNum; } const Twine &getMsg() const { return Msg; } private: /// Name of the input file associated with this diagnostic. StringRef FileName; /// Line number where the diagnostic occurred. If 0, no line number will /// be emitted in the message. unsigned LineNum = 0; /// Message to report. const Twine &Msg; }; /// Diagnostic information for the PGO profiler. class DiagnosticInfoPGOProfile : public DiagnosticInfo { public: DiagnosticInfoPGOProfile(const char *FileName, const Twine &Msg, DiagnosticSeverity Severity = DS_Error) : DiagnosticInfo(DK_PGOProfile, Severity), FileName(FileName), Msg(Msg) {} /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_PGOProfile; } const char *getFileName() const { return FileName; } const Twine &getMsg() const { return Msg; } private: /// Name of the input file associated with this diagnostic. const char *FileName; /// Message to report. const Twine &Msg; }; class DiagnosticLocation { DIFile *File = nullptr; unsigned Line = 0; unsigned Column = 0; public: DiagnosticLocation() = default; DiagnosticLocation(const DebugLoc &DL); DiagnosticLocation(const DISubprogram *SP); bool isValid() const { return File; } /// Return the full path to the file. std::string getAbsolutePath() const; /// Return the file name relative to the compilation directory. StringRef getRelativePath() const; unsigned getLine() const { return Line; } unsigned getColumn() const { return Column; } }; /// Common features for diagnostics with an associated location. class DiagnosticInfoWithLocationBase : public DiagnosticInfo { void anchor() override; public: /// \p Fn is the function where the diagnostic is being emitted. \p Loc is /// the location information to use in the diagnostic. DiagnosticInfoWithLocationBase(enum DiagnosticKind Kind, enum DiagnosticSeverity Severity, const Function &Fn, const DiagnosticLocation &Loc) : DiagnosticInfo(Kind, Severity), Fn(Fn), Loc(Loc) {} /// Return true if location information is available for this diagnostic. bool isLocationAvailable() const { return Loc.isValid(); } /// Return a string with the location information for this diagnostic /// in the format "file:line:col". If location information is not available, /// it returns ":0:0". std::string getLocationStr() const; /// Return location information for this diagnostic in three parts: /// the relative source file path, line number and column. void getLocation(StringRef &RelativePath, unsigned &Line, unsigned &Column) const; /// Return the absolute path tot the file. std::string getAbsolutePath() const; const Function &getFunction() const { return Fn; } DiagnosticLocation getLocation() const { return Loc; } private: /// Function where this diagnostic is triggered. const Function &Fn; /// Debug location where this diagnostic is triggered. DiagnosticLocation Loc; }; /// Diagnostic information for stack size etc. reporting. /// This is basically a function and a size. class DiagnosticInfoResourceLimit : public DiagnosticInfoWithLocationBase { private: /// The function that is concerned by this resource limit diagnostic. const Function &Fn; /// Description of the resource type (e.g. stack size) const char *ResourceName; /// The computed size usage uint64_t ResourceSize; // Threshould passed uint64_t ResourceLimit; public: /// \p The function that is concerned by this stack size diagnostic. /// \p The computed stack size. DiagnosticInfoResourceLimit(const Function &Fn, const char *ResourceName, uint64_t ResourceSize, uint64_t ResourceLimit, DiagnosticSeverity Severity = DS_Warning, DiagnosticKind Kind = DK_ResourceLimit); const Function &getFunction() const { return Fn; } const char *getResourceName() const { return ResourceName; } uint64_t getResourceSize() const { return ResourceSize; } uint64_t getResourceLimit() const { return ResourceLimit; } /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_ResourceLimit || DI->getKind() == DK_StackSize; } }; class DiagnosticInfoStackSize : public DiagnosticInfoResourceLimit { void anchor() override; public: DiagnosticInfoStackSize(const Function &Fn, uint64_t StackSize, uint64_t StackLimit, DiagnosticSeverity Severity = DS_Warning) : DiagnosticInfoResourceLimit(Fn, "stack frame size", StackSize, StackLimit, Severity, DK_StackSize) {} uint64_t getStackSize() const { return getResourceSize(); } uint64_t getStackLimit() const { return getResourceLimit(); } static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_StackSize; } }; /// Common features for diagnostics dealing with optimization remarks /// that are used by both IR and MIR passes. class DiagnosticInfoOptimizationBase : public DiagnosticInfoWithLocationBase { public: /// Used to set IsVerbose via the stream interface. struct setIsVerbose {}; /// When an instance of this is inserted into the stream, the arguments /// following will not appear in the remark printed in the compiler output /// (-Rpass) but only in the optimization record file /// (-fsave-optimization-record). struct setExtraArgs {}; /// Used in the streaming interface as the general argument type. It /// internally converts everything into a key-value pair. struct Argument { std::string Key; std::string Val; // If set, the debug location corresponding to the value. DiagnosticLocation Loc; explicit Argument(StringRef Str = "") : Key("String"), Val(Str) {} Argument(StringRef Key, const Value *V); Argument(StringRef Key, const Type *T); Argument(StringRef Key, StringRef S); Argument(StringRef Key, const char *S) : Argument(Key, StringRef(S)) {}; Argument(StringRef Key, int N); Argument(StringRef Key, float N); Argument(StringRef Key, long N); Argument(StringRef Key, long long N); Argument(StringRef Key, unsigned N); Argument(StringRef Key, unsigned long N); Argument(StringRef Key, unsigned long long N); Argument(StringRef Key, ElementCount EC); Argument(StringRef Key, bool B) : Key(Key), Val(B ? "true" : "false") {} Argument(StringRef Key, DebugLoc dl); Argument(StringRef Key, InstructionCost C); }; /// \p PassName is the name of the pass emitting this diagnostic. \p /// RemarkName is a textual identifier for the remark (single-word, /// camel-case). \p Fn is the function where the diagnostic is being emitted. /// \p Loc is the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code /// location. DiagnosticInfoOptimizationBase(enum DiagnosticKind Kind, enum DiagnosticSeverity Severity, const char *PassName, StringRef RemarkName, const Function &Fn, const DiagnosticLocation &Loc) : DiagnosticInfoWithLocationBase(Kind, Severity, Fn, Loc), PassName(PassName), RemarkName(RemarkName) {} void insert(StringRef S); void insert(Argument A); void insert(setIsVerbose V); void insert(setExtraArgs EA); /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; /// Return true if this optimization remark is enabled by one of /// of the LLVM command line flags (-pass-remarks, -pass-remarks-missed, /// or -pass-remarks-analysis). Note that this only handles the LLVM /// flags. We cannot access Clang flags from here (they are handled /// in BackendConsumer::OptimizationRemarkHandler). virtual bool isEnabled() const = 0; StringRef getPassName() const { return PassName; } StringRef getRemarkName() const { return RemarkName; } std::string getMsg() const; std::optional getHotness() const { return Hotness; } void setHotness(std::optional H) { Hotness = H; } bool isVerbose() const { return IsVerbose; } ArrayRef getArgs() const { return Args; } static bool classof(const DiagnosticInfo *DI) { return (DI->getKind() >= DK_FirstRemark && DI->getKind() <= DK_LastRemark) || (DI->getKind() >= DK_FirstMachineRemark && DI->getKind() <= DK_LastMachineRemark); } bool isPassed() const { return (getKind() == DK_OptimizationRemark || getKind() == DK_MachineOptimizationRemark); } bool isMissed() const { return (getKind() == DK_OptimizationRemarkMissed || getKind() == DK_MachineOptimizationRemarkMissed); } bool isAnalysis() const { return (getKind() == DK_OptimizationRemarkAnalysis || getKind() == DK_MachineOptimizationRemarkAnalysis); } protected: /// Name of the pass that triggers this report. If this matches the /// regular expression given in -Rpass=regexp, then the remark will /// be emitted. const char *PassName; /// Textual identifier for the remark (single-word, camel-case). Can be used /// by external tools reading the output file for optimization remarks to /// identify the remark. StringRef RemarkName; /// If profile information is available, this is the number of times the /// corresponding code was executed in a profile instrumentation run. std::optional Hotness; /// Arguments collected via the streaming interface. SmallVector Args; /// The remark is expected to be noisy. bool IsVerbose = false; /// If positive, the index of the first argument that only appear in /// the optimization records and not in the remark printed in the compiler /// output. int FirstExtraArgIndex = -1; }; /// Allow the insertion operator to return the actual remark type rather than a /// common base class. This allows returning the result of the insertion /// directly by value, e.g. return OptimizationRemarkAnalysis(...) << "blah". template RemarkT & operator<<(RemarkT &R, std::enable_if_t< std::is_base_of::value, StringRef> S) { R.insert(S); return R; } /// Also allow r-value for the remark to allow insertion into a /// temporarily-constructed remark. template RemarkT & operator<<(RemarkT &&R, std::enable_if_t< std::is_base_of::value, StringRef> S) { R.insert(S); return R; } template RemarkT & operator<<(RemarkT &R, std::enable_if_t< std::is_base_of::value, DiagnosticInfoOptimizationBase::Argument> A) { R.insert(A); return R; } template RemarkT & operator<<(RemarkT &&R, std::enable_if_t< std::is_base_of::value, DiagnosticInfoOptimizationBase::Argument> A) { R.insert(A); return R; } template RemarkT & operator<<(RemarkT &R, std::enable_if_t< std::is_base_of::value, DiagnosticInfoOptimizationBase::setIsVerbose> V) { R.insert(V); return R; } template RemarkT & operator<<(RemarkT &&R, std::enable_if_t< std::is_base_of::value, DiagnosticInfoOptimizationBase::setIsVerbose> V) { R.insert(V); return R; } template RemarkT & operator<<(RemarkT &R, std::enable_if_t< std::is_base_of::value, DiagnosticInfoOptimizationBase::setExtraArgs> EA) { R.insert(EA); return R; } /// Common features for diagnostics dealing with optimization remarks /// that are used by IR passes. class DiagnosticInfoIROptimization : public DiagnosticInfoOptimizationBase { void anchor() override; public: /// \p PassName is the name of the pass emitting this diagnostic. \p /// RemarkName is a textual identifier for the remark (single-word, /// camel-case). \p Fn is the function where the diagnostic is being emitted. /// \p Loc is the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code /// location. \p CodeRegion is IR value (currently basic block) that the /// optimization operates on. This is currently used to provide run-time /// hotness information with PGO. DiagnosticInfoIROptimization(enum DiagnosticKind Kind, enum DiagnosticSeverity Severity, const char *PassName, StringRef RemarkName, const Function &Fn, const DiagnosticLocation &Loc, const Value *CodeRegion = nullptr) : DiagnosticInfoOptimizationBase(Kind, Severity, PassName, RemarkName, Fn, Loc), CodeRegion(CodeRegion) {} /// This is ctor variant allows a pass to build an optimization remark /// from an existing remark. /// /// This is useful when a transformation pass (e.g LV) wants to emit a remark /// (\p Orig) generated by one of its analyses (e.g. LAA) as its own analysis /// remark. The string \p Prepend will be emitted before the original /// message. DiagnosticInfoIROptimization(const char *PassName, StringRef Prepend, const DiagnosticInfoIROptimization &Orig) : DiagnosticInfoOptimizationBase( (DiagnosticKind)Orig.getKind(), Orig.getSeverity(), PassName, Orig.RemarkName, Orig.getFunction(), Orig.getLocation()), CodeRegion(Orig.getCodeRegion()) { *this << Prepend; std::copy(Orig.Args.begin(), Orig.Args.end(), std::back_inserter(Args)); } /// Legacy interface. /// \p PassName is the name of the pass emitting this diagnostic. /// \p Fn is the function where the diagnostic is being emitted. \p Loc is /// the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code /// location. \p Msg is the message to show. Note that this class does not /// copy this message, so this reference must be valid for the whole life time /// of the diagnostic. DiagnosticInfoIROptimization(enum DiagnosticKind Kind, enum DiagnosticSeverity Severity, const char *PassName, const Function &Fn, const DiagnosticLocation &Loc, const Twine &Msg) : DiagnosticInfoOptimizationBase(Kind, Severity, PassName, "", Fn, Loc) { *this << Msg.str(); } const Value *getCodeRegion() const { return CodeRegion; } static bool classof(const DiagnosticInfo *DI) { return DI->getKind() >= DK_FirstRemark && DI->getKind() <= DK_LastRemark; } private: /// The IR value (currently basic block) that the optimization operates on. /// This is currently used to provide run-time hotness information with PGO. const Value *CodeRegion = nullptr; }; /// Diagnostic information for applied optimization remarks. class OptimizationRemark : public DiagnosticInfoIROptimization { 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 (single- /// word, camel-case). \p Loc is the debug location and \p CodeRegion is the /// region that the optimization operates on (currently only block is /// supported). OptimizationRemark(const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc, const Value *CodeRegion); /// Same as above, but the debug location and code region are derived from \p /// Instr. OptimizationRemark(const char *PassName, StringRef RemarkName, const Instruction *Inst); /// Same as above, but the debug location and code region are derived from \p /// Func. OptimizationRemark(const char *PassName, StringRef RemarkName, const Function *Func); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemark; } /// \see DiagnosticInfoOptimizationBase::isEnabled. bool isEnabled() const override; private: /// This is deprecated now and only used by the function API below. /// \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 Fn is the function where the diagnostic /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic /// will include the source code location. \p Msg is the message to show. /// Note that this class does not copy this message, so this reference /// must be valid for the whole life time of the diagnostic. OptimizationRemark(const char *PassName, const Function &Fn, const DiagnosticLocation &Loc, const Twine &Msg) : DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName, Fn, Loc, Msg) {} }; /// Diagnostic information for missed-optimization remarks. class OptimizationRemarkMissed : public DiagnosticInfoIROptimization { 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 (single-word, camel-case). \p Loc is the debug location and \p /// CodeRegion is the region that the optimization operates on (currently only /// block is supported). OptimizationRemarkMissed(const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc, const Value *CodeRegion); /// Same as above but \p Inst is used to derive code region and debug /// location. OptimizationRemarkMissed(const char *PassName, StringRef RemarkName, const Instruction *Inst); /// Same as above but \p F is used to derive code region and debug /// location. OptimizationRemarkMissed(const char *PassName, StringRef RemarkName, const Function *F); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkMissed; } /// \see DiagnosticInfoOptimizationBase::isEnabled. bool isEnabled() const override; private: /// This is deprecated now and only used by the function API below. /// \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 Fn is the function where the diagnostic /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic /// will include the source code location. \p Msg is the message to show. /// Note that this class does not copy this message, so this reference /// must be valid for the whole life time of the diagnostic. OptimizationRemarkMissed(const char *PassName, const Function &Fn, const DiagnosticLocation &Loc, const Twine &Msg) : DiagnosticInfoIROptimization(DK_OptimizationRemarkMissed, DS_Remark, PassName, Fn, Loc, Msg) {} }; /// Diagnostic information for optimization analysis remarks. class OptimizationRemarkAnalysis : public DiagnosticInfoIROptimization { 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 (single-word, camel-case). \p Loc is the debug location and \p /// CodeRegion is the region that the optimization operates on (currently only /// block is supported). OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc, const Value *CodeRegion); /// This is ctor variant allows a pass to build an optimization remark /// from an existing remark. /// /// This is useful when a transformation pass (e.g LV) wants to emit a remark /// (\p Orig) generated by one of its analyses (e.g. LAA) as its own analysis /// remark. The string \p Prepend will be emitted before the original /// message. OptimizationRemarkAnalysis(const char *PassName, StringRef Prepend, const OptimizationRemarkAnalysis &Orig) : DiagnosticInfoIROptimization(PassName, Prepend, Orig) {} /// Same as above but \p Inst is used to derive code region and debug /// location. OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, const Instruction *Inst); /// Same as above but \p F is used to derive code region and debug /// location. OptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, const Function *F); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkAnalysis; } /// \see DiagnosticInfoOptimizationBase::isEnabled. bool isEnabled() const override; static const char *AlwaysPrint; bool shouldAlwaysPrint() const { return getPassName() == AlwaysPrint; } protected: OptimizationRemarkAnalysis(enum DiagnosticKind Kind, const char *PassName, const Function &Fn, const DiagnosticLocation &Loc, const Twine &Msg) : DiagnosticInfoIROptimization(Kind, DS_Remark, PassName, Fn, Loc, Msg) {} OptimizationRemarkAnalysis(enum DiagnosticKind Kind, const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc, const Value *CodeRegion); private: /// This is deprecated now and only used by the function API below. /// \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 Fn is the function where the diagnostic /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic will /// include the source code location. \p Msg is the message to show. Note that /// this class does not copy this message, so this reference must be valid for /// the whole life time of the diagnostic. OptimizationRemarkAnalysis(const char *PassName, const Function &Fn, const DiagnosticLocation &Loc, const Twine &Msg) : DiagnosticInfoIROptimization(DK_OptimizationRemarkAnalysis, DS_Remark, PassName, Fn, Loc, Msg) {} }; /// Diagnostic information for optimization analysis remarks related to /// floating-point non-commutativity. class OptimizationRemarkAnalysisFPCommute : public OptimizationRemarkAnalysis { void anchor() override; 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 (single-word, camel-case). \p Loc is the debug location and \p /// CodeRegion is the region that the optimization operates on (currently only /// block is supported). The front-end will append its own message related to /// options that address floating-point non-commutativity. OptimizationRemarkAnalysisFPCommute(const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc, const Value *CodeRegion) : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisFPCommute, PassName, RemarkName, Loc, CodeRegion) {} static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkAnalysisFPCommute; } private: /// This is deprecated now and only used by the function API below. /// \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 Fn is the function where the diagnostic /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic will /// include the source code location. \p Msg is the message to show. The /// front-end will append its own message related to options that address /// floating-point non-commutativity. Note that this class does not copy this /// message, so this reference must be valid for the whole life time of the /// diagnostic. OptimizationRemarkAnalysisFPCommute(const char *PassName, const Function &Fn, const DiagnosticLocation &Loc, const Twine &Msg) : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisFPCommute, PassName, Fn, Loc, Msg) {} }; /// Diagnostic information for optimization analysis remarks related to /// pointer aliasing. class OptimizationRemarkAnalysisAliasing : public OptimizationRemarkAnalysis { void anchor() override; 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 (single-word, camel-case). \p Loc is the debug location and \p /// CodeRegion is the region that the optimization operates on (currently only /// block is supported). The front-end will append its own message related to /// options that address pointer aliasing legality. OptimizationRemarkAnalysisAliasing(const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc, const Value *CodeRegion) : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisAliasing, PassName, RemarkName, Loc, CodeRegion) {} static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationRemarkAnalysisAliasing; } private: /// This is deprecated now and only used by the function API below. /// \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 Fn is the function where the diagnostic /// is being emitted. \p Loc is the location information to use in the /// diagnostic. If line table information is available, the diagnostic will /// include the source code location. \p Msg is the message to show. The /// front-end will append its own message related to options that address /// pointer aliasing legality. Note that this class does not copy this /// message, so this reference must be valid for the whole life time of the /// diagnostic. OptimizationRemarkAnalysisAliasing(const char *PassName, const Function &Fn, const DiagnosticLocation &Loc, const Twine &Msg) : OptimizationRemarkAnalysis(DK_OptimizationRemarkAnalysisAliasing, PassName, Fn, Loc, Msg) {} }; /// Diagnostic information for machine IR parser. // FIXME: Remove this, use DiagnosticInfoSrcMgr instead. class DiagnosticInfoMIRParser : public DiagnosticInfo { const SMDiagnostic &Diagnostic; public: DiagnosticInfoMIRParser(DiagnosticSeverity Severity, const SMDiagnostic &Diagnostic) : DiagnosticInfo(DK_MIRParser, Severity), Diagnostic(Diagnostic) {} const SMDiagnostic &getDiagnostic() const { return Diagnostic; } void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_MIRParser; } }; /// Diagnostic information for ISel fallback path. class DiagnosticInfoISelFallback : public DiagnosticInfo { /// The function that is concerned by this diagnostic. const Function &Fn; public: DiagnosticInfoISelFallback(const Function &Fn, DiagnosticSeverity Severity = DS_Warning) : DiagnosticInfo(DK_ISelFallback, Severity), Fn(Fn) {} const Function &getFunction() const { return Fn; } void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_ISelFallback; } }; // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DiagnosticInfo, LLVMDiagnosticInfoRef) /// Diagnostic information for optimization failures. class DiagnosticInfoOptimizationFailure : public DiagnosticInfoIROptimization { public: /// \p Fn is the function where the diagnostic is being emitted. \p Loc is /// the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code /// location. \p Msg is the message to show. Note that this class does not /// copy this message, so this reference must be valid for the whole life time /// of the diagnostic. DiagnosticInfoOptimizationFailure(const Function &Fn, const DiagnosticLocation &Loc, const Twine &Msg) : DiagnosticInfoIROptimization(DK_OptimizationFailure, DS_Warning, nullptr, Fn, Loc, Msg) {} /// \p PassName is the name of the pass emitting this diagnostic. \p /// RemarkName is a textual identifier for the remark (single-word, /// camel-case). \p Loc is the debug location and \p CodeRegion is the /// region that the optimization operates on (currently basic block is /// supported). DiagnosticInfoOptimizationFailure(const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc, const Value *CodeRegion); static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_OptimizationFailure; } /// \see DiagnosticInfoOptimizationBase::isEnabled. bool isEnabled() const override; }; /// Diagnostic information for unsupported feature in backend. class DiagnosticInfoUnsupported : public DiagnosticInfoWithLocationBase { private: Twine Msg; public: /// \p Fn is the function where the diagnostic is being emitted. \p Loc is /// the location information to use in the diagnostic. If line table /// information is available, the diagnostic will include the source code /// location. \p Msg is the message to show. Note that this class does not /// copy this message, so this reference must be valid for the whole life time /// of the diagnostic. DiagnosticInfoUnsupported( const Function &Fn, const Twine &Msg, const DiagnosticLocation &Loc = DiagnosticLocation(), DiagnosticSeverity Severity = DS_Error) : DiagnosticInfoWithLocationBase(DK_Unsupported, Severity, Fn, Loc), Msg(Msg) {} static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_Unsupported; } const Twine &getMessage() const { return Msg; } void print(DiagnosticPrinter &DP) const override; }; /// Diagnostic information for MisExpect analysis. class DiagnosticInfoMisExpect : public DiagnosticInfoWithLocationBase { public: DiagnosticInfoMisExpect(const Instruction *Inst, Twine &Msg); /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_MisExpect; } const Twine &getMsg() const { return Msg; } private: /// Message to report. const Twine &Msg; }; static DiagnosticSeverity getDiagnosticSeverity(SourceMgr::DiagKind DK) { switch (DK) { case llvm::SourceMgr::DK_Error: return DS_Error; break; case llvm::SourceMgr::DK_Warning: return DS_Warning; break; case llvm::SourceMgr::DK_Note: return DS_Note; break; case llvm::SourceMgr::DK_Remark: return DS_Remark; break; } llvm_unreachable("unknown SourceMgr::DiagKind"); } /// Diagnostic information for SMDiagnostic reporting. class DiagnosticInfoSrcMgr : public DiagnosticInfo { const SMDiagnostic &Diagnostic; StringRef ModName; // For inlineasm !srcloc translation. bool InlineAsmDiag; unsigned LocCookie; public: DiagnosticInfoSrcMgr(const SMDiagnostic &Diagnostic, StringRef ModName, bool InlineAsmDiag = true, unsigned LocCookie = 0) : DiagnosticInfo(DK_SrcMgr, getDiagnosticSeverity(Diagnostic.getKind())), Diagnostic(Diagnostic), ModName(ModName), InlineAsmDiag(InlineAsmDiag), LocCookie(LocCookie) {} StringRef getModuleName() const { return ModName; } bool isInlineAsmDiag() const { return InlineAsmDiag; } const SMDiagnostic &getSMDiag() const { return Diagnostic; } unsigned getLocCookie() const { return LocCookie; } void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_SrcMgr; } }; void diagnoseDontCall(const CallInst &CI); class DiagnosticInfoDontCall : public DiagnosticInfo { StringRef CalleeName; StringRef Note; unsigned LocCookie; public: DiagnosticInfoDontCall(StringRef CalleeName, StringRef Note, DiagnosticSeverity DS, unsigned LocCookie) : DiagnosticInfo(DK_DontCall, DS), CalleeName(CalleeName), Note(Note), LocCookie(LocCookie) {} StringRef getFunctionName() const { return CalleeName; } StringRef getNote() const { return Note; } unsigned getLocCookie() const { return LocCookie; } void print(DiagnosticPrinter &DP) const override; static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_DontCall; } }; } // end namespace llvm #endif // LLVM_IR_DIAGNOSTICINFO_H