[PATCH] Add warning capabilities in LLVM (backend part), Take 2

Tom Stellard tom at stellard.net
Fri Dec 13 19:22:25 PST 2013


On Wed, Dec 11, 2013 at 10:26:50AM -0800, Quentin Colombet wrote:
> Hi Tom,
> 
> On Dec 10, 2013, at 5:02 PM, Tom Stellard <tom at stellard.net> wrote:
> 
> > On Tue, Dec 10, 2013 at 04:31:36PM -0800, Quentin Colombet wrote:
> >> Hi dblaikie, rengolin, chandlerc, echristo,
> >> 
> >> Hi,
> >> 
> > 
> > Hi Quentin,
> > 
> > Thanks for continuing to work on this, I think this will be a very
> > useful feature.
> > 
> >> This patch implements the latest  proposal discussed a few weeks ago regarding adding warning capabilities in LLVM.
> >> The original RFC:
> >> http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-July/063845.html
> >> 
> >> The latest discussion with the new design:
> >> http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20131111/195244.html
> >> http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20131118/195627.html 
> >> 
> >> //// Overview ////
> >> 
> >> The patch adds a new LLVMContext::diagnose that can be used to communicate to the front-end, if any, that something of interest happened.
> >> The diagnostics are supported by a new abstraction, the DiagnosticInfo class.
> >> The base class contains the following information:
> >> - The kind of the report: What this is this about.
> >> - The severity of the report: How bad this is.
> >> 
> >> This patch also adds 3 classes:
> >> - DiagnosticInfoInlineAsm: For inline asm reporting. Basically, this diagnostic will be used to switch to the new diagnostic API for LLVMContext::emitError.
> >> - DiagnosticStackSize: For stack size reporting. Comes as a replacement of the hard coded warning in PEI.
> >> - DiagnosticOther: For all other reporting. Features a message with %[0-9]+ specifiers and an array of values. Each specifier will be replaced by the printing of the related index from the array of values.
> >> 
> >> This patch introduces a new DiagnosticHandlerTy and a new DiagnosticContext that should be set by the front-end to be able to map these diagnostics in its own system.
> >> 
> >> //// Next Steps ////
> >> 
> >> - Send the patch for clang (I have it on hold).
> >> - Switch to this reporting for all warnings printing happening in the backend (i.e., get rid of the hard coded warnings).
> >> - Switch LLVMContext::emitError to the new diagnostic API.
> >> - Add an entry in LLVM documentation about this diagnostic reporting feature.
> >> 
> >> //// Open Questions ////
> >> 
> >> - Should we make SMDiagnostic a sub class of DiagnosticInfo?
> >> The idea would be to get rid of the InlineAsmDiagHandler.
> >> 
> >> - Do we want to provide a C API for this?
> > 
> > I would like to see this in the C API.  If there is no C API when I
> > start integrating this into Mesa (which may not be for several months),
> > I can add it myself.
> Based on your comment, I guess we can move forward with that proposal and look into the C API as a second step.
> Is this right?
> 
> Just to be sure we are on the right track, looking into the current proposal are you seeing anything missing or anything that will obviously not work with a C API?
> 

I'm not really an expert on what will or won't work with the C API, but
at least for my purposes I think it will work out.

-Tom

> > 
> >> 
> >> - Do we want to extend that to fatal error as well?
> >> That would be a nice homogenization of the framework (replace (some of) the calls to report_fatal_error).
> >> 
> > 
> > I'm not sure what 'that' refers to here, but I am in favor of replacing as
> > many calls to report_fatal_error() as possible (preferably all of them).
> > This is especially important for API implementations, like OpenCL that
> > use LLVM as a library, because those APIs need to be able to report errors
> > to the user.  Handling errors by calling exit() is not really acceptable.
> Agree.
> 
> Thanks for your feedbacks.
> 
> -Quentin
> 
> > 
> > -Tom
> > 
> >> Thanks for your reviews.
> >> 
> >> Cheers,
> >> Quentin
> >> 
> >> PS: Hal, DiagnosticPrinter class does not include SCEV or MachineInstr because these are not part of the IR library.
> >> 
> >> http://llvm-reviews.chandlerc.com/D2376
> >> 
> >> Files:
> >>  include/llvm/IR/LLVMContext.h
> >>  include/llvm/Support/DiagnosticInfo.h
> >>  include/llvm/Support/DiagnosticPrinter.h
> >>  lib/CodeGen/PrologEpilogInserter.cpp
> >>  lib/IR/LLVMContext.cpp
> >>  lib/IR/LLVMContextImpl.cpp
> >>  lib/IR/LLVMContextImpl.h
> >>  lib/Support/CMakeLists.txt
> >>  lib/Support/DiagnosticInfo.cpp
> >>  lib/Support/DiagnosticPrinter.cpp
> >>  test/CodeGen/ARM/warn-stack.ll
> >>  test/CodeGen/X86/warn-stack.ll
> > 
> >> Index: include/llvm/IR/LLVMContext.h
> >> ===================================================================
> >> --- include/llvm/IR/LLVMContext.h
> >> +++ include/llvm/IR/LLVMContext.h
> >> @@ -27,6 +27,7 @@
> >> class Instruction;
> >> class Module;
> >> class SMDiagnostic;
> >> +class DiagnosticInfo;
> >> template <typename T> class SmallVectorImpl;
> >> 
> >> /// This is an important class for using LLVM in a threaded context.  It
> >> @@ -64,6 +65,11 @@
> >>   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 @@
> >>   /// 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 code should be prepared to drop the
> >> +  /// erroneous construct on the floor and "not crash".
> >> +  /// 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
> >> Index: include/llvm/Support/DiagnosticInfo.h
> >> ===================================================================
> >> --- include/llvm/Support/DiagnosticInfo.h
> >> +++ include/llvm/Support/DiagnosticInfo.h
> >> @@ -0,0 +1,192 @@
> >> +//===- 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;
> >> +
> >> +/// Defines the different supported severity of a diagnostic.
> >> +enum DiagnosticSeverity {
> >> +  DS_Error,
> >> +  DS_Warning,
> >> +  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_StackSize,
> >> +  DK_Other
> >> +};
> >> +
> >> +/// 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 Kind;
> >> +  /// Severity gives the severity of the diagnostic.
> >> +  const DiagnosticSeverity Severity;
> >> +
> >> +public:
> >> +  DiagnosticInfo(DiagnosticKind Kind, DiagnosticSeverity Severity)
> >> +      : Kind(Kind), Severity(Severity) {}
> >> +
> >> +  virtual ~DiagnosticInfo() {}
> >> +
> >> +  DiagnosticKind 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;
> >> +  }
> >> +};
> >> +
> >> +/// Diagnostic information for all other diagnostics.
> >> +/// This consists in a message string that uses a %[0-9]+ and
> >> +/// an array of arguments.
> >> +/// For printing, each %i specifier is replaced by the printing of Vals[i].
> >> +/// E.g., the message string: "Something weird happens in %0, with analysis
> >> +/// %1, and %0 seems broken", use Vals[0], Vals[1], and Vals[0] again.
> >> +class DiagnosticInfoOther : public DiagnosticInfo {
> >> +public:
> >> +  // Shortcut for arguments type.
> >> +  typedef ArrayRef<Value *> Values;
> >> +
> >> +private:
> >> +  /// Message string using %[0-9]+ for argument specifier.
> >> +  const Twine &MsgStr;
> >> +  /// Array of arguments.
> >> +  Values Vals;
> >> +
> >> +public:
> >> +  /// \p MsgStr gives the message to be reported using %[0-9]+ specifier to
> >> +  /// indicate where to print the related argument given by \p Vals.
> >> +  /// To issue a '%' character, one has to escape it with another '%'
> >> +  /// character. Thus, to issue '%' character, use "%%".
> >> +  DiagnosticInfoOther(const Twine &MsgStr, Values Vals,
> >> +                      DiagnosticSeverity Severity)
> >> +      : DiagnosticInfo(DK_Other, Severity), MsgStr(MsgStr), Vals(Vals) {}
> >> +
> >> +  const Twine &getMsgStr() const { return MsgStr; }
> >> +  Values getVals() const { return Vals; }
> >> +
> >> +  /// \see DiagnosticInfo::print.
> >> +  virtual void print(DiagnosticPrinter &DP) const;
> >> +
> >> +  /// Hand rolled RTTI.
> >> +  static bool classof(const DiagnosticInfo *DI) {
> >> +    return DI->getKind() == DK_Other;
> >> +  }
> >> +};
> >> +
> >> +} // End namespace llvm
> >> +
> >> +#endif
> >> Index: include/llvm/Support/DiagnosticPrinter.h
> >> ===================================================================
> >> --- include/llvm/Support/DiagnosticPrinter.h
> >> +++ include/llvm/Support/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 <string>
> >> +
> >> +namespace llvm {
> >> +// Forward declarations.
> >> +class raw_ostream;
> >> +class StringRef;
> >> +class Twine;
> >> +class Value;
> >> +
> >> +/// 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;
> >> +};
> >> +
> >> +/// 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
> >> Index: lib/CodeGen/PrologEpilogInserter.cpp
> >> ===================================================================
> >> --- lib/CodeGen/PrologEpilogInserter.cpp
> >> +++ lib/CodeGen/PrologEpilogInserter.cpp
> >> @@ -30,9 +30,11 @@
> >> #include "llvm/CodeGen/MachineRegisterInfo.h"
> >> #include "llvm/CodeGen/RegisterScavenging.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"
> >> +#include "llvm/Support/DiagnosticInfo.h"
> >> #include "llvm/Support/raw_ostream.h"
> >> #include "llvm/Target/TargetFrameLowering.h"
> >> #include "llvm/Target/TargetInstrInfo.h"
> >> @@ -160,10 +162,11 @@
> >> 
> >>   // 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();
> >> Index: lib/IR/LLVMContext.cpp
> >> ===================================================================
> >> --- lib/IR/LLVMContext.cpp
> >> +++ lib/IR/LLVMContext.cpp
> >> @@ -17,6 +17,8 @@
> >> #include "llvm/IR/Constants.h"
> >> #include "llvm/IR/Instruction.h"
> >> #include "llvm/IR/Metadata.h"
> >> +#include "llvm/Support/DiagnosticInfo.h"
> >> +#include "llvm/Support/DiagnosticPrinter.h"
> >> #include "llvm/Support/ManagedStatic.h"
> >> #include "llvm/Support/SourceMgr.h"
> >> #include <cctype>
> >> @@ -98,6 +100,20 @@
> >>   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 @@
> >>   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) {
> >> Index: lib/IR/LLVMContextImpl.cpp
> >> ===================================================================
> >> --- lib/IR/LLVMContextImpl.cpp
> >> +++ lib/IR/LLVMContextImpl.cpp
> >> @@ -37,6 +37,8 @@
> >>     Int64Ty(C, 64) {
> >>   InlineAsmDiagHandler = 0;
> >>   InlineAsmDiagContext = 0;
> >> +  DiagnosticHandler = 0;
> >> +  DiagnosticContext = 0;
> >>   NamedStructTypesUniqueID = 0;
> >> }
> >> 
> >> Index: lib/IR/LLVMContextImpl.h
> >> ===================================================================
> >> --- lib/IR/LLVMContextImpl.h
> >> +++ lib/IR/LLVMContextImpl.h
> >> @@ -238,9 +238,12 @@
> >> 
> >>   LLVMContext::InlineAsmDiagHandlerTy InlineAsmDiagHandler;
> >>   void *InlineAsmDiagContext;
> >> -  
> >> -  typedef DenseMap<DenseMapAPIntKeyInfo::KeyTy, ConstantInt*, 
> >> -                         DenseMapAPIntKeyInfo> IntMapTy;
> >> +
> >> +  LLVMContext::DiagnosticHandlerTy DiagnosticHandler;
> >> +  void *DiagnosticContext;
> >> +
> >> +  typedef DenseMap<DenseMapAPIntKeyInfo::KeyTy, ConstantInt *,
> >> +                   DenseMapAPIntKeyInfo> IntMapTy;
> >>   IntMapTy IntConstants;
> >> 
> >>   typedef DenseMap<DenseMapAPFloatKeyInfo::KeyTy, ConstantFP*, 
> >> Index: lib/Support/CMakeLists.txt
> >> ===================================================================
> >> --- lib/Support/CMakeLists.txt
> >> +++ lib/Support/CMakeLists.txt
> >> @@ -17,6 +17,8 @@
> >>   Debug.cpp
> >>   DeltaAlgorithm.cpp
> >>   DAGDeltaAlgorithm.cpp
> >> +  DiagnosticInfo.cpp
> >> +  DiagnosticPrinter.cpp
> >>   Dwarf.cpp
> >>   ErrorHandling.cpp
> >>   FileUtilities.cpp
> >> Index: lib/Support/DiagnosticInfo.cpp
> >> ===================================================================
> >> --- lib/Support/DiagnosticInfo.cpp
> >> +++ lib/Support/DiagnosticInfo.cpp
> >> @@ -0,0 +1,98 @@
> >> +//===- 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/Function.h"
> >> +#include "llvm/IR/Instruction.h"
> >> +#include "llvm/IR/Metadata.h"
> >> +#include "llvm/Support/DiagnosticInfo.h"
> >> +#include "llvm/Support/DiagnosticPrinter.h"
> >> +
> >> +#include <string>
> >> +
> >> +using namespace llvm;
> >> +
> >> +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<ConstantInt>(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();
> >> +}
> >> +
> >> +void DiagnosticInfoOther::print(DiagnosticPrinter &DP) const {
> >> +  // Look for %[0-9]+ and insert the related argument.
> >> +  std::string Msg = MsgStr.str();
> >> +  // True if the scan of the string is currently in a %[0-9]+ mode.
> >> +  bool ArgIdxBuildMode = false;
> >> +  // Keep track of the ArgIdx when building it through the %[0-9]+ syntax.
> >> +  int ArgIdx = -1;
> >> +  for (std::string::const_iterator ItMsg = Msg.begin(), ItMsgEnd = Msg.end();
> >> +       ItMsg != ItMsgEnd; ++ItMsg) {
> >> +    const char Cur = *ItMsg;
> >> +    // Check if we are inside of a %[0-9]+
> >> +    if (ArgIdxBuildMode) {
> >> +      // if we are keeping seeing [0-9], update the ArgIdx accordingly.
> >> +      if (Cur >= '0' && Cur <= '9') {
> >> +        if (ArgIdx == -1)
> >> +          ArgIdx = 0;
> >> +        ArgIdx *= 10;
> >> +        ArgIdx += Cur - '0';
> >> +        continue;
> >> +      }
> >> +      // No more argument index building, emit the related argument and
> >> +      // keep going. In particular fallthrough the default path to emit the
> >> +      // current character.
> >> +
> >> +      // If the argument index is invalid, this means we are excaping
> >> +      // '%', thus the substring must be "%%".
> >> +      assert((ArgIdx > -1 || Cur == '%') &&
> >> +             "Invalid string format (did not found \"%%\" or \"%[0-9]+\").");
> >> +      if (ArgIdx > -1) {
> >> +        assert(((size_t)ArgIdx) < Vals.size() && "Invalid argument index.");
> >> +        DP << Vals[ArgIdx];
> >> +      }
> >> +      ArgIdxBuildMode = false;
> >> +      ArgIdx = -1;
> >> +    } else if (Cur == '%') {
> >> +      ArgIdxBuildMode = true;
> >> +      continue;
> >> +    }
> >> +    DP << Cur;
> >> +  }
> >> +  // Print any remaining argument.
> >> +  // If ArgIdx == -1, this means MsgStr ends with a single '%',
> >> +  // which is invalid.
> >> +  if (ArgIdxBuildMode) {
> >> +    assert(ArgIdx > -1 && "Invalid string format (trailing '%').");
> >> +    assert(((size_t)ArgIdx) < Vals.size() && "Invalid argument index.");
> >> +    DP << Vals[ArgIdx];
> >> +  }
> >> +}
> >> Index: lib/Support/DiagnosticPrinter.cpp
> >> ===================================================================
> >> --- lib/Support/DiagnosticPrinter.cpp
> >> +++ lib/Support/DiagnosticPrinter.cpp
> >> @@ -0,0 +1,103 @@
> >> +//===- 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/Analysis/ScalarEvolution.h"
> >> +#include "llvm/CodeGen/MachineInstr.h"
> >> +#include "llvm/IR/Value.h"
> >> +#include "llvm/Support/DiagnosticPrinter.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;
> >> +}
> >> Index: test/CodeGen/ARM/warn-stack.ll
> >> ===================================================================
> >> --- test/CodeGen/ARM/warn-stack.ll
> >> +++ test/CodeGen/ARM/warn-stack.ll
> >> @@ -12,7 +12,7 @@
> >>   ret void
> >> }
> >> 
> >> -; CHECK: warning: Stack size limit exceeded (96) in warn.
> >> +; CHECK: warning: stack size limit exceeded (96) in warn
> >> define void @warn() nounwind ssp {
> >> entry:
> >>   %buffer = alloca [80 x i8], align 1
> >> Index: test/CodeGen/X86/warn-stack.ll
> >> ===================================================================
> >> --- test/CodeGen/X86/warn-stack.ll
> >> +++ test/CodeGen/X86/warn-stack.ll
> >> @@ -12,7 +12,7 @@
> >>   ret void
> >> }
> >> 
> >> -; CHECK: warning: Stack size limit exceeded (104) in warn.
> >> +; CHECK: warning: stack size limit exceeded (104) in warn
> >> define void @warn() nounwind ssp {
> >> entry:
> >>   %buffer = alloca [80 x i8], align 1
> > 
> >> _______________________________________________
> >> llvm-commits mailing list
> >> llvm-commits at cs.uiuc.edu
> >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
> 



More information about the llvm-commits mailing list