diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h new file mode 100644 index 000000000000..151e155eaf85 --- /dev/null +++ b/llvm/include/llvm/IR/DiagnosticInfo.h @@ -0,0 +1,165 @@ +//===- llvm/Support/DiagnosticInfo.h - Diagnostic Declaration ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the different classes involved in low level diagnostics. +// +// Diagnostics reporting is still done as part of the LLVMContext. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_DIAGNOSTICINFO_H +#define LLVM_SUPPORT_DIAGNOSTICINFO_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Casting.h" + +namespace llvm { + +// Forward declarations. +class DiagnosticPrinter; +class Function; +class Instruction; +class Twine; +class Value; + +/// \brief Defines the different supported severity of a diagnostic. +enum DiagnosticSeverity { + DS_Error, + DS_Warning, + DS_Note +}; + +/// \brief 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_StackSize, + DK_FirstPluginKind +}; + +/// \brief 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(); + +/// \brief 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; + +public: + DiagnosticInfo(/* DiagnosticKind */ int Kind, DiagnosticSeverity Severity) + : Kind(Kind), Severity(Severity) {} + + virtual ~DiagnosticInfo() {} + + /* 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; +}; + +/// 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. + unsigned LocCookie; + /// Message to be reported. + const Twine &MsgStr; + /// Optional origin of the problem. + const Instruction *Instr; + +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), LocCookie(0), MsgStr(MsgStr), + Instr(NULL) {} + + /// \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(unsigned LocCookie, const Twine &MsgStr, + DiagnosticSeverity Severity = DS_Error) + : DiagnosticInfo(DK_InlineAsm, Severity), LocCookie(LocCookie), + MsgStr(MsgStr), Instr(NULL) {} + + /// \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); + + unsigned getLocCookie() const { return LocCookie; } + const Twine &getMsgStr() const { return MsgStr; } + const Instruction *getInstruction() const { return Instr; } + + /// \see DiagnosticInfo::print. + virtual void print(DiagnosticPrinter &DP) const; + + /// Hand rolled RTTI. + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_InlineAsm; + } +}; + +/// Diagnostic information for stack size reporting. +/// This is basically a function and a size. +class DiagnosticInfoStackSize : public DiagnosticInfo { +private: + /// The function that is concerned by this stack size diagnostic. + const Function &Fn; + /// The computed stack size. + unsigned StackSize; + +public: + /// \p The function that is concerned by this stack size diagnostic. + /// \p The computed stack size. + DiagnosticInfoStackSize(const Function &Fn, unsigned StackSize, + DiagnosticSeverity Severity = DS_Warning) + : DiagnosticInfo(DK_StackSize, Severity), Fn(Fn), StackSize(StackSize) {} + + const Function &getFunction() const { return Fn; } + unsigned getStackSize() const { return StackSize; } + + /// \see DiagnosticInfo::print. + virtual void print(DiagnosticPrinter &DP) const; + + /// Hand rolled RTTI. + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_StackSize; + } +}; + +} // End namespace llvm + +#endif diff --git a/llvm/include/llvm/IR/DiagnosticPrinter.h b/llvm/include/llvm/IR/DiagnosticPrinter.h new file mode 100644 index 000000000000..721b1b4212e0 --- /dev/null +++ b/llvm/include/llvm/IR/DiagnosticPrinter.h @@ -0,0 +1,84 @@ +//===- llvm/Support/DiagnosticPrinter.h - Diagnostic Printer ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the main interface for printer backend diagnostic. +// +// Clients of the backend diagnostics should overload this interface based +// on their needs. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_DIAGNOSTICPRINTER_H +#define LLVM_SUPPORT_DIAGNOSTICPRINTER_H + +#include + +namespace llvm { +// Forward declarations. +class raw_ostream; +class StringRef; +class Twine; +class Value; + +/// \brief Interface for custom diagnostic printing. +class DiagnosticPrinter { +public: + virtual ~DiagnosticPrinter() {} + + // Simple types. + virtual DiagnosticPrinter &operator<<(char C) = 0; + virtual DiagnosticPrinter &operator<<(unsigned char C) = 0; + virtual DiagnosticPrinter &operator<<(signed char C) = 0; + virtual DiagnosticPrinter &operator<<(StringRef Str) = 0; + virtual DiagnosticPrinter &operator<<(const char *Str) = 0; + virtual DiagnosticPrinter &operator<<(const std::string &Str) = 0; + virtual DiagnosticPrinter &operator<<(unsigned long N) = 0; + virtual DiagnosticPrinter &operator<<(long N) = 0; + virtual DiagnosticPrinter &operator<<(unsigned long long N) = 0; + virtual DiagnosticPrinter &operator<<(long long N) = 0; + virtual DiagnosticPrinter &operator<<(const void *P) = 0; + virtual DiagnosticPrinter &operator<<(unsigned int N) = 0; + virtual DiagnosticPrinter &operator<<(int N) = 0; + virtual DiagnosticPrinter &operator<<(double N) = 0; + virtual DiagnosticPrinter &operator<<(const Twine &Str) = 0; + + // IR related types. + virtual DiagnosticPrinter &operator<<(const Value &V) = 0; +}; + +/// \brief Basic diagnostic printer that uses an underlying raw_ostream. +class DiagnosticPrinterRawOStream : public DiagnosticPrinter { +protected: + raw_ostream &Stream; + +public: + DiagnosticPrinterRawOStream(raw_ostream &Stream) : Stream(Stream) {}; + + // Simple types. + virtual DiagnosticPrinter &operator<<(char C); + virtual DiagnosticPrinter &operator<<(unsigned char C); + virtual DiagnosticPrinter &operator<<(signed char C); + virtual DiagnosticPrinter &operator<<(StringRef Str); + virtual DiagnosticPrinter &operator<<(const char *Str); + virtual DiagnosticPrinter &operator<<(const std::string &Str); + virtual DiagnosticPrinter &operator<<(unsigned long N); + virtual DiagnosticPrinter &operator<<(long N); + virtual DiagnosticPrinter &operator<<(unsigned long long N); + virtual DiagnosticPrinter &operator<<(long long N); + virtual DiagnosticPrinter &operator<<(const void *P); + virtual DiagnosticPrinter &operator<<(unsigned int N); + virtual DiagnosticPrinter &operator<<(int N); + virtual DiagnosticPrinter &operator<<(double N); + virtual DiagnosticPrinter &operator<<(const Twine &Str); + + // IR related types. + virtual DiagnosticPrinter &operator<<(const Value &V); +}; +} // End namespace llvm + +#endif diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h index dd379ae5e72c..b80f7c82db24 100644 --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -27,6 +27,7 @@ class Twine; class Instruction; class Module; class SMDiagnostic; +class DiagnosticInfo; template class SmallVectorImpl; /// This is an important class for using LLVM in a threaded context. It @@ -64,6 +65,11 @@ public: typedef void (*InlineAsmDiagHandlerTy)(const SMDiagnostic&, void *Context, unsigned LocCookie); + /// Defines the type of a diagnostic handler. + /// \see LLVMContext::setDiagnosticHandler. + /// \see LLVMContext::diagnose. + typedef void (*DiagnosticHandlerTy)(const DiagnosticInfo &DI, void *Context); + /// setInlineAsmDiagnosticHandler - This method sets a handler that is invoked /// when problems with inline asm are detected by the backend. The first /// argument is a function pointer and the second is a context pointer that @@ -82,6 +88,33 @@ public: /// setInlineAsmDiagnosticHandler. void *getInlineAsmDiagnosticContext() const; + /// setDiagnosticHandler - This method sets a handler that is invoked + /// when the backend needs to report anything to the user. The first + /// argument is a function pointer and the second is a context pointer that + /// gets passed into the DiagHandler. + /// + /// LLVMContext doesn't take ownership or interpret either of these + /// pointers. + void setDiagnosticHandler(DiagnosticHandlerTy DiagHandler, + void *DiagContext = 0); + + /// getDiagnosticHandler - Return the diagnostic handler set by + /// setDiagnosticHandler. + DiagnosticHandlerTy getDiagnosticHandler() const; + + /// getDiagnosticContext - Return the diagnostic context set by + /// setDiagnosticContext. + void *getDiagnosticContext() const; + + /// diagnose - Report a message to the currently installed diagnostic handler. + /// This function returns, in particular in the case of error reporting + /// (DI.Severity == RS_Error), so the caller should leave the compilation + /// process in a self-consistent state, even though the generated code + /// need not be correct. + /// The diagnostic message will be implicitly prefixed with a severity + /// keyword according to \p DI.getSeverity(), i.e., "error: " + /// for RS_Error, "warning: " for RS_Warning, and "note: " for RS_Note. + void diagnose(const DiagnosticInfo &DI); /// emitError - Emit an error message to the currently installed error handler /// with optional location information. This function returns, so code should diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp index 0107a9cb442c..9e6997999129 100644 --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -29,7 +29,9 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/InlineAsm.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" @@ -160,10 +162,11 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) { // Warn on stack size when we exceeds the given limit. MachineFrameInfo *MFI = Fn.getFrameInfo(); - if (WarnStackSize.getNumOccurrences() > 0 && - WarnStackSize < MFI->getStackSize()) - errs() << "warning: Stack size limit exceeded (" << MFI->getStackSize() - << ") in " << Fn.getName() << ".\n"; + uint64_t StackSize = MFI->getStackSize(); + if (WarnStackSize.getNumOccurrences() > 0 && WarnStackSize < StackSize) { + DiagnosticInfoStackSize DiagStackSize(*F, StackSize); + F->getContext().diagnose(DiagStackSize); + } delete RS; ReturnBlocks.clear(); diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt index 581946c5486f..b825583bf370 100644 --- a/llvm/lib/IR/CMakeLists.txt +++ b/llvm/lib/IR/CMakeLists.txt @@ -6,6 +6,8 @@ add_llvm_library(LLVMCore ConstantFold.cpp Constants.cpp Core.cpp + DiagnosticInfo.cpp + DiagnosticPrinter.cpp DIBuilder.cpp DataLayout.cpp DebugInfo.cpp diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp new file mode 100644 index 000000000000..0db962691f5e --- /dev/null +++ b/llvm/lib/IR/DiagnosticInfo.cpp @@ -0,0 +1,54 @@ +//===- llvm/Support/DiagnosticInfo.cpp - Diagnostic Definitions -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the different classes involved in low level diagnostics. +// +// Diagnostics reporting is still done as part of the LLVMContext. +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Twine.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Metadata.h" +#include "llvm/Support/Atomic.h" + +#include + +using namespace llvm; + +int getNextAvailablePluginDiagnosticKind() { + static sys::cas_flag PluginKindID = DK_FirstPluginKind; + return (int)sys::AtomicIncrement(&PluginKindID); +} + +DiagnosticInfoInlineAsm::DiagnosticInfoInlineAsm(const Instruction &I, + const Twine &MsgStr, + DiagnosticSeverity Severity) + : DiagnosticInfo(DK_InlineAsm, Severity), LocCookie(0), MsgStr(MsgStr), + Instr(&I) { + if (const MDNode *SrcLoc = I.getMetadata("srcloc")) { + if (SrcLoc->getNumOperands() != 0) + if (const ConstantInt *CI = dyn_cast(SrcLoc->getOperand(0))) + LocCookie = CI->getZExtValue(); + } +} + +void DiagnosticInfoInlineAsm::print(DiagnosticPrinter &DP) const { + DP << getMsgStr(); + if (getLocCookie()) + DP << " at line " << getLocCookie(); +} + +void DiagnosticInfoStackSize::print(DiagnosticPrinter &DP) const { + DP << "stack size limit exceeded (" << getStackSize() << ") in " + << getFunction(); +} diff --git a/llvm/lib/IR/DiagnosticPrinter.cpp b/llvm/lib/IR/DiagnosticPrinter.cpp new file mode 100644 index 000000000000..04cd6c7e6f7e --- /dev/null +++ b/llvm/lib/IR/DiagnosticPrinter.cpp @@ -0,0 +1,101 @@ +//===- llvm/Support/DiagnosticInfo.cpp - Diagnostic Definitions -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the a diagnostic printer relying on raw_ostream. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Twine.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(char C) { + Stream << C; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(unsigned char C) { + Stream << C; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(signed char C) { + Stream << C; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(StringRef Str) { + Stream << Str; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const char *Str) { + Stream << Str; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<( + const std::string &Str) { + Stream << Str; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(unsigned long N) { + Stream << N; + return *this; +} +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(long N) { + Stream << N; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<( + unsigned long long N) { + Stream << N; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(long long N) { + Stream << N; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const void *P) { + Stream << P; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(unsigned int N) { + Stream << N; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(int N) { + Stream << N; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(double N) { + Stream << N; + return *this; +} + +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const Twine &Str) { + Stream << Str.getSingleStringRef(); + return *this; +} + +// IR related types. +DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const Value &V) { + Stream << V.getName(); + return *this; +} diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp index 883bb9878fa5..bae83dd30155 100644 --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -15,6 +15,8 @@ #include "llvm/IR/LLVMContext.h" #include "LLVMContextImpl.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/ManagedStatic.h" @@ -98,6 +100,20 @@ void *LLVMContext::getInlineAsmDiagnosticContext() const { return pImpl->InlineAsmDiagContext; } +void LLVMContext::setDiagnosticHandler(DiagnosticHandlerTy DiagnosticHandler, + void *DiagnosticContext) { + pImpl->DiagnosticHandler = DiagnosticHandler; + pImpl->DiagnosticContext = DiagnosticContext; +} + +LLVMContext::DiagnosticHandlerTy LLVMContext::getDiagnosticHandler() const { + return pImpl->DiagnosticHandler; +} + +void *LLVMContext::getDiagnosticContext() const { + return pImpl->DiagnosticContext; +} + void LLVMContext::emitError(const Twine &ErrorStr) { emitError(0U, ErrorStr); } @@ -112,6 +128,31 @@ void LLVMContext::emitError(const Instruction *I, const Twine &ErrorStr) { return emitError(LocCookie, ErrorStr); } +void LLVMContext::diagnose(const DiagnosticInfo &DI) { + // If there is a report handler, use it. + if (pImpl->DiagnosticHandler != 0) { + pImpl->DiagnosticHandler(DI, pImpl->DiagnosticContext); + return; + } + // Otherwise, print the message with a prefix based on the severity. + std::string MsgStorage; + raw_string_ostream Stream(MsgStorage); + DiagnosticPrinterRawOStream DP(Stream); + DI.print(DP); + Stream.flush(); + switch (DI.getSeverity()) { + case DS_Error: + errs() << "error: " << MsgStorage << "\n"; + exit(1); + case DS_Warning: + errs() << "warning: " << MsgStorage << "\n"; + break; + case DS_Note: + errs() << "note: " << MsgStorage << "\n"; + break; + } +} + void LLVMContext::emitError(unsigned LocCookie, const Twine &ErrorStr) { // If there is no error handler installed, just print the error and exit. if (pImpl->InlineAsmDiagHandler == 0) { diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp index 6a6a4d6801f0..ebff9d3a51f6 100644 --- a/llvm/lib/IR/LLVMContextImpl.cpp +++ b/llvm/lib/IR/LLVMContextImpl.cpp @@ -37,6 +37,8 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C) Int64Ty(C, 64) { InlineAsmDiagHandler = 0; InlineAsmDiagContext = 0; + DiagnosticHandler = 0; + DiagnosticContext = 0; NamedStructTypesUniqueID = 0; } diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 407b9856892a..39e5d778ed68 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -238,9 +238,12 @@ public: LLVMContext::InlineAsmDiagHandlerTy InlineAsmDiagHandler; void *InlineAsmDiagContext; - - typedef DenseMap IntMapTy; + + LLVMContext::DiagnosticHandlerTy DiagnosticHandler; + void *DiagnosticContext; + + typedef DenseMap IntMapTy; IntMapTy IntConstants; typedef DenseMap