My Project
Diagnostics.h
Go to the documentation of this file.
1 //===- Diagnostics.h - MLIR Diagnostics -------------------------*- C++ -*-===//
2 //
3 // Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines utilities for emitting diagnostics.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef MLIR_IR_DIAGNOSTICS_H
14 #define MLIR_IR_DIAGNOSTICS_H
15 
16 #include "mlir/IR/Location.h"
17 #include "mlir/Support/STLExtras.h"
18 #include <functional>
19 
20 namespace llvm {
21 class MemoryBuffer;
22 class SMLoc;
23 class SourceMgr;
24 } // end namespace llvm
25 
26 namespace mlir {
27 class DiagnosticEngine;
28 class Identifier;
29 struct LogicalResult;
30 class MLIRContext;
31 class Operation;
32 class OperationName;
33 class Type;
34 
35 namespace detail {
36 struct DiagnosticEngineImpl;
37 } // end namespace detail
38 
40 enum class DiagnosticSeverity {
41  Note,
42  Warning,
43  Error,
44  Remark,
45 };
46 
47 //===----------------------------------------------------------------------===//
48 // DiagnosticArgument
49 //===----------------------------------------------------------------------===//
50 
53 public:
57  Attribute,
58  Double,
59  Integer,
60  Operation,
61  String,
62  Type,
63  Unsigned,
64  };
65 
67  void print(raw_ostream &os) const;
68 
70  DiagnosticArgumentKind getKind() const { return kind; }
71 
73  Attribute getAsAttribute() const;
74 
76  double getAsDouble() const {
77  assert(getKind() == DiagnosticArgumentKind::Double);
78  return doubleVal;
79  }
80 
82  int64_t getAsInteger() const {
83  assert(getKind() == DiagnosticArgumentKind::Integer);
84  return static_cast<int64_t>(opaqueVal);
85  }
86 
89  assert(getKind() == DiagnosticArgumentKind::Operation);
90  return *reinterpret_cast<Operation *>(opaqueVal);
91  }
92 
94  StringRef getAsString() const {
95  assert(getKind() == DiagnosticArgumentKind::String);
96  return stringVal;
97  }
98 
100  Type getAsType() const;
101 
103  uint64_t getAsUnsigned() const {
104  assert(getKind() == DiagnosticArgumentKind::Unsigned);
105  return static_cast<uint64_t>(opaqueVal);
106  }
107 
108 private:
109  friend class Diagnostic;
110 
111  // Construct from an Attribute.
112  explicit DiagnosticArgument(Attribute attr);
113 
114  // Construct from a floating point number.
115  explicit DiagnosticArgument(double val)
116  : kind(DiagnosticArgumentKind::Double), doubleVal(val) {}
117  explicit DiagnosticArgument(float val) : DiagnosticArgument(double(val)) {}
118 
119  // Construct from a signed integer.
120  template <typename T>
121  explicit DiagnosticArgument(
122  T val, typename std::enable_if<std::is_signed<T>::value &&
123  std::numeric_limits<T>::is_integer &&
124  sizeof(T) <= sizeof(int64_t)>::type * = 0)
125  : kind(DiagnosticArgumentKind::Integer), opaqueVal(int64_t(val)) {}
126 
127  // Construct from an unsigned integer.
128  template <typename T>
129  explicit DiagnosticArgument(
130  T val, typename std::enable_if<std::is_unsigned<T>::value &&
131  std::numeric_limits<T>::is_integer &&
132  sizeof(T) <= sizeof(uint64_t)>::type * = 0)
133  : kind(DiagnosticArgumentKind::Unsigned), opaqueVal(uint64_t(val)) {}
134 
135  // Construct from an operation reference.
136  explicit DiagnosticArgument(Operation &val) : DiagnosticArgument(&val) {}
137  explicit DiagnosticArgument(Operation *val)
139  opaqueVal(reinterpret_cast<intptr_t>(val)) {
140  assert(val && "expected valid operation");
141  }
142 
143  // Construct from a string reference.
144  explicit DiagnosticArgument(StringRef val)
145  : kind(DiagnosticArgumentKind::String), stringVal(val) {}
146 
147  // Construct from a Type.
148  explicit DiagnosticArgument(Type val);
149 
152 
154  union {
155  double doubleVal;
156  intptr_t opaqueVal;
157  StringRef stringVal;
158  };
159 };
160 
161 inline raw_ostream &operator<<(raw_ostream &os, const DiagnosticArgument &arg) {
162  arg.print(os);
163  return os;
164 }
165 
166 //===----------------------------------------------------------------------===//
167 // Diagnostic
168 //===----------------------------------------------------------------------===//
169 
173 class Diagnostic {
174  using NoteVector = std::vector<std::unique_ptr<Diagnostic>>;
175 
178  template <typename IteratorTy, typename NotePtrTy = decltype(*IteratorTy()),
179  typename ResultTy = decltype(**IteratorTy())>
180  class NoteIteratorImpl
181  : public llvm::mapped_iterator<IteratorTy, ResultTy (*)(NotePtrTy)> {
182  static ResultTy &unwrap(NotePtrTy note) { return *note; }
183 
184  public:
185  NoteIteratorImpl(IteratorTy it)
186  : llvm::mapped_iterator<IteratorTy, ResultTy (*)(NotePtrTy)>(it,
187  &unwrap) {}
188  };
189 
190 public:
192  : loc(loc), severity(severity) {}
193  Diagnostic(Diagnostic &&) = default;
194  Diagnostic &operator=(Diagnostic &&) = default;
195 
197  DiagnosticSeverity getSeverity() const { return severity; }
198 
200  Location getLocation() const { return loc; }
201 
204  ArrayRef<DiagnosticArgument> getArguments() const { return arguments; }
205 
207  template <typename Arg>
208  typename std::enable_if<!std::is_convertible<Arg, StringRef>::value,
209  Diagnostic &>::type
210  operator<<(Arg &&val) {
211  arguments.push_back(DiagnosticArgument(std::forward<Arg>(val)));
212  return *this;
213  }
214 
216  Diagnostic &operator<<(const char *val) {
217  arguments.push_back(DiagnosticArgument(val));
218  return *this;
219  }
220 
222  Diagnostic &operator<<(char val);
223  Diagnostic &operator<<(const Twine &val);
224  Diagnostic &operator<<(Twine &&val);
225 
228 
231 
233  template <typename T> Diagnostic &operator<<(iterator_range<T> range) {
234  return appendRange(range);
235  }
236  template <typename T> Diagnostic &operator<<(ArrayRef<T> range) {
237  return appendRange(range);
238  }
239 
242  template <typename T, template <typename> class Container>
243  Diagnostic &appendRange(const Container<T> &c, const char *delim = ", ") {
244  interleave(
245  c, [&](const detail::ValueOfRange<Container<T>> &a) { *this << a; },
246  [&]() { *this << delim; });
247  return *this;
248  }
249 
251  template <typename Arg1, typename Arg2, typename... Args>
252  Diagnostic &append(Arg1 &&arg1, Arg2 &&arg2, Args &&... args) {
253  append(std::forward<Arg1>(arg1));
254  return append(std::forward<Arg2>(arg2), std::forward<Args>(args)...);
255  }
257  template <typename Arg> Diagnostic &append(Arg &&arg) {
258  *this << std::forward<Arg>(arg);
259  return *this;
260  }
261 
263  void print(raw_ostream &os) const;
264 
266  std::string str() const;
267 
271  Diagnostic &attachNote(Optional<Location> noteLoc = llvm::None);
272 
273  using note_iterator = NoteIteratorImpl<NoteVector::iterator>;
274  using const_note_iterator = NoteIteratorImpl<NoteVector::const_iterator>;
275 
278  return {notes.begin(), notes.end()};
279  }
281  return {notes.begin(), notes.end()};
282  }
283 
285  operator LogicalResult() const;
286 
287 private:
288  Diagnostic(const Diagnostic &rhs) = delete;
289  Diagnostic &operator=(const Diagnostic &rhs) = delete;
290 
292  Location loc;
293 
295  DiagnosticSeverity severity;
296 
299 
302  std::vector<std::unique_ptr<char[]>> strings;
303 
305  NoteVector notes;
306 };
307 
308 inline raw_ostream &operator<<(raw_ostream &os, const Diagnostic &diag) {
309  diag.print(os);
310  return os;
311 }
312 
313 //===----------------------------------------------------------------------===//
314 // InFlightDiagnostic
315 //===----------------------------------------------------------------------===//
316 
321 public:
322  InFlightDiagnostic() = default;
324  : owner(rhs.owner), impl(std::move(rhs.impl)) {
325  // Reset the rhs diagnostic.
326  rhs.impl.reset();
327  rhs.abandon();
328  }
330  if (isInFlight())
331  report();
332  }
333 
335  template <typename Arg> InFlightDiagnostic &operator<<(Arg &&arg) & {
336  return append(std::forward<Arg>(arg));
337  }
338  template <typename Arg> InFlightDiagnostic &&operator<<(Arg &&arg) && {
339  return std::move(append(std::forward<Arg>(arg)));
340  }
341 
343  template <typename... Args> InFlightDiagnostic &append(Args &&... args) & {
344  assert(isActive() && "diagnostic not active");
345  if (isInFlight())
346  impl->append(std::forward<Args>(args)...);
347  return *this;
348  }
349  template <typename... Args> InFlightDiagnostic &&append(Args &&... args) && {
350  return std::move(append(std::forward<Args>(args)...));
351  }
352 
355  assert(isActive() && "diagnostic not active");
356  return impl->attachNote(noteLoc);
357  }
358 
360  void report();
361 
363  void abandon();
364 
367  operator LogicalResult() const;
368 
369 private:
370  InFlightDiagnostic &operator=(const InFlightDiagnostic &) = delete;
371  InFlightDiagnostic &operator=(InFlightDiagnostic &&) = delete;
373  : owner(owner), impl(std::move(rhs)) {}
374 
376  bool isActive() const { return impl.hasValue(); }
377 
379  bool isInFlight() const { return owner; }
380 
381  // Allow access to the constructor.
382  friend DiagnosticEngine;
383 
385  DiagnosticEngine *owner = nullptr;
386 
389 };
390 
391 //===----------------------------------------------------------------------===//
392 // DiagnosticEngine
393 //===----------------------------------------------------------------------===//
394 
400 public:
401  ~DiagnosticEngine();
402 
403  // Diagnostic handler registration and use. MLIR supports the ability for the
404  // IR to carry arbitrary metadata about operation location information. If a
405  // problem is detected by the compiler, it can invoke the emitError /
406  // emitWarning / emitRemark method on an Operation and have it get reported
407  // through this interface.
408  //
409  // Tools using MLIR are encouraged to register error handlers and define a
410  // schema for their location information. If they don't, then warnings and
411  // notes will be dropped and errors will be emitted to errs.
412 
416  using HandlerTy = std::function<LogicalResult(Diagnostic &)>;
417 
419  using HandlerID = uint64_t;
420 
426  HandlerID registerHandler(const HandlerTy &handler);
427 
431  template <typename FuncTy, typename RetT = decltype(std::declval<FuncTy>()(
432  std::declval<Diagnostic &>()))>
433  std::enable_if_t<std::is_same<RetT, void>::value, HandlerID>
434  registerHandler(FuncTy &&handler) {
435  return registerHandler([=](Diagnostic &diag) {
436  handler(diag);
437  return success();
438  });
439  }
440 
442  void eraseHandler(HandlerID id);
443 
446  assert(severity != DiagnosticSeverity::Note &&
447  "notes should not be emitted directly");
448  return InFlightDiagnostic(this, Diagnostic(loc, severity));
449  }
450 
453  void emit(Diagnostic diag);
454 
455 private:
456  friend class MLIRContextImpl;
458 
460  std::unique_ptr<detail::DiagnosticEngineImpl> impl;
461 };
462 
465 InFlightDiagnostic emitError(Location loc, const Twine &message);
466 
469 InFlightDiagnostic emitWarning(Location loc, const Twine &message);
470 
473 InFlightDiagnostic emitRemark(Location loc, const Twine &message);
474 
480 template <typename... Args>
482  if (loc)
483  return emitError(*loc).append(std::forward<Args>(args)...);
484  return failure();
485 }
486 template <typename... Args>
488  if (loc)
489  return emitWarning(*loc).append(std::forward<Args>(args)...);
490  return failure();
491 }
492 template <typename... Args>
494  if (loc)
495  return emitRemark(*loc).append(std::forward<Args>(args)...);
496  return failure();
497 }
498 
499 //===----------------------------------------------------------------------===//
500 // ScopedDiagnosticHandler
501 //===----------------------------------------------------------------------===//
502 
507 public:
508  explicit ScopedDiagnosticHandler(MLIRContext *ctx) : handlerID(0), ctx(ctx) {}
509  template <typename FuncTy>
510  ScopedDiagnosticHandler(MLIRContext *ctx, FuncTy &&handler)
511  : handlerID(0), ctx(ctx) {
512  setHandler(std::forward<FuncTy>(handler));
513  }
515 
516 protected:
518  template <typename FuncTy> void setHandler(FuncTy &&handler) {
519  auto &diagEngine = ctx->getDiagEngine();
520  if (handlerID)
521  diagEngine.eraseHandler(handlerID);
522  handlerID = diagEngine.registerHandler(std::forward<FuncTy>(handler));
523  }
524 
525 private:
527  DiagnosticEngine::HandlerID handlerID;
528 
530  MLIRContext *ctx;
531 };
532 
533 //===----------------------------------------------------------------------===//
534 // SourceMgrDiagnosticHandler
535 //===----------------------------------------------------------------------===//
536 
537 namespace detail {
538 struct SourceMgrDiagnosticHandlerImpl;
539 } // end namespace detail
540 
543 public:
544  SourceMgrDiagnosticHandler(llvm::SourceMgr &mgr, MLIRContext *ctx,
545  raw_ostream &os);
546  SourceMgrDiagnosticHandler(llvm::SourceMgr &mgr, MLIRContext *ctx);
548 
550  void emitDiagnostic(Location loc, Twine message, DiagnosticSeverity kind);
551 
552 protected:
554  void emitDiagnostic(Diagnostic &diag);
555 
558  const llvm::MemoryBuffer *getBufferForFile(StringRef filename);
559 
561  llvm::SourceMgr &mgr;
562 
564  raw_ostream &os;
565 
566 private:
568  llvm::SMLoc convertLocToSMLoc(FileLineColLoc loc);
569 
572  unsigned callStackLimit = 10;
573 
574  std::unique_ptr<detail::SourceMgrDiagnosticHandlerImpl> impl;
575 };
576 
577 //===----------------------------------------------------------------------===//
578 // SourceMgrDiagnosticVerifierHandler
579 //===----------------------------------------------------------------------===//
580 
581 namespace detail {
582 struct SourceMgrDiagnosticVerifierHandlerImpl;
583 } // end namespace detail
584 
589 public:
590  SourceMgrDiagnosticVerifierHandler(llvm::SourceMgr &srcMgr, MLIRContext *ctx,
591  raw_ostream &out);
592  SourceMgrDiagnosticVerifierHandler(llvm::SourceMgr &srcMgr, MLIRContext *ctx);
594 
599 
600 private:
602  void process(Diagnostic &diag);
603 
605  void process(FileLineColLoc loc, StringRef msg, DiagnosticSeverity kind);
606 
607  std::unique_ptr<detail::SourceMgrDiagnosticVerifierHandlerImpl> impl;
608 };
609 
610 //===----------------------------------------------------------------------===//
611 // ParallelDiagnosticHandler
612 //===----------------------------------------------------------------------===//
613 
614 namespace detail {
615 struct ParallelDiagnosticHandlerImpl;
616 } // end namespace detail
617 
623 public:
626 
638  void setOrderIDForThread(size_t orderID);
639 
642  void eraseOrderIDForThread();
643 
644 private:
645  std::unique_ptr<detail::ParallelDiagnosticHandlerImpl> impl;
646 };
647 } // namespace mlir
648 
649 #endif
Definition: InferTypeOpInterface.cpp:20
Definition: PassRegistry.cpp:413
Definition: Operation.h:27
InFlightDiagnostic(InFlightDiagnostic &&rhs)
Definition: Diagnostics.h:323
Definition: Attributes.h:139
void setHandler(FuncTy &&handler)
Set the handler to manage via RAII.
Definition: Diagnostics.h:518
Definition: Diagnostics.h:320
LogicalResult emitOptionalRemark(Optional< Location > loc, Args &&... args)
Definition: Diagnostics.h:493
Definition: MLIRContext.cpp:149
Definition: Diagnostics.h:506
uint64_t getAsUnsigned() const
Returns this argument as an unsigned integer.
Definition: Diagnostics.h:103
Location getLocation() const
Returns the source location for this diagnostic.
Definition: Diagnostics.h:200
Definition: Identifier.h:26
NoteIteratorImpl< NoteVector::iterator > note_iterator
Definition: Diagnostics.h:273
Diagnostic & appendRange(const Container< T > &c, const char *delim=", ")
Definition: Diagnostics.h:243
int64_t getAsInteger() const
Returns this argument as a signed integer.
Definition: Diagnostics.h:82
void print(raw_ostream &os) const
Outputs this argument to a stream.
Definition: Diagnostics.cpp:63
InFlightDiagnostic emitRemark(Location loc, const Twine &message)
Definition: Diagnostics.cpp:318
Operation & getAsOperation() const
Returns this argument as an operation.
Definition: Diagnostics.h:88
DiagnosticSeverity getSeverity() const
Returns the severity of this diagnostic.
Definition: Diagnostics.h:197
DiagnosticSeverity
Defines the different supported severity of a diagnostic.
Definition: Diagnostics.h:40
Definition: LLVM.h:40
Definition: Location.h:52
LogicalResult emitOptionalError(Optional< Location > loc, Args &&... args)
Definition: Diagnostics.h:481
InFlightDiagnostic emitWarning(Location loc, const Twine &message)
Definition: Diagnostics.cpp:310
LogicalResult success(bool isSuccess=true)
Definition: LogicalResult.h:25
Definition: Diagnostics.h:173
Definition: LogicalResult.h:18
Definition: Diagnostics.h:622
LogicalResult failure(bool isFailure=true)
Definition: LogicalResult.h:32
Definition: LLVM.h:37
InFlightDiagnostic && append(Args &&... args) &&
Definition: Diagnostics.h:349
LogicalResult emitOptionalWarning(Optional< Location > loc, Args &&... args)
Definition: Diagnostics.h:487
uint64_t HandlerID
A handle to a specific registered handler object.
Definition: Diagnostics.h:419
StringRef getAsString() const
Returns this argument as a string.
Definition: Diagnostics.h:94
raw_ostream & os
The output stream to use when printing diagnostics.
Definition: Diagnostics.h:564
void print(raw_ostream &os) const
Outputs this diagnostic to a stream.
Definition: Diagnostics.cpp:135
Diagnostic & attachNote(Optional< Location > noteLoc=llvm::None)
Attaches a note to this diagnostic.
Definition: Diagnostics.h:354
InFlightDiagnostic emitError(Location loc, const Twine &message)
Definition: Diagnostics.cpp:302
Definition: Attributes.h:53
Definition: LLVM.h:38
~InFlightDiagnostic()
Definition: Diagnostics.h:329
StringRef stringVal
Definition: Diagnostics.h:157
DiagnosticArgumentKind
Definition: Diagnostics.h:56
Diagnostic(Location loc, DiagnosticSeverity severity)
Definition: Diagnostics.h:191
ArrayRef< DiagnosticArgument > getArguments() const
Definition: Diagnostics.h:204
MutableArrayRef< DiagnosticArgument > getArguments()
Returns the current list of diagnostic arguments.
Definition: Diagnostics.h:203
Diagnostic & append(Arg1 &&arg1, Arg2 &&arg2, Args &&... args)
Append arguments to the diagnostic.
Definition: Diagnostics.h:252
DiagnosticArgumentKind getKind() const
Returns the kind of this argument.
Definition: Diagnostics.h:70
Definition: Types.h:84
This class is a utility diagnostic handler for use with llvm::SourceMgr.
Definition: Diagnostics.h:542
Definition: Diagnostics.h:399
InFlightDiagnostic && operator<<(Arg &&arg) &&
Definition: Diagnostics.h:338
Definition: Attributes.h:137
A variant type that holds a single argument for a diagnostic.
Definition: Diagnostics.h:52
Definition: LLVM.h:35
void interleave(ForwardIterator begin, ForwardIterator end, UnaryFunctor each_fn, NullaryFunctor between_fn)
Definition: STLExtras.h:43
ScopedDiagnosticHandler(MLIRContext *ctx)
Definition: Diagnostics.h:508
Definition: Diagnostics.h:588
InFlightDiagnostic emit(Location loc, DiagnosticSeverity severity)
Create a new inflight diagnostic with the given location and severity.
Definition: Diagnostics.h:445
LogicalResult verify(AffinePrefetchOp op)
Definition: AffineOps.cpp:2078
Diagnostic & operator<<(const char *val)
Stream in a string literal.
Definition: Diagnostics.h:216
iterator_range< note_iterator > getNotes()
Returns the notes held by this diagnostic.
Definition: Diagnostics.h:277
std::function< LogicalResult(Diagnostic &)> HandlerTy
Definition: Diagnostics.h:416
Definition: LLVM.h:50
std::enable_if_t< std::is_same< RetT, void >::value, HandlerID > registerHandler(FuncTy &&handler)
Definition: Diagnostics.h:434
std::ostream & operator<<(std::ostream &out, const llvm::Twine &twine)
Definition: DebugStringHelper.h:36
llvm::SourceMgr & mgr
The source manager that we are wrapping.
Definition: Diagnostics.h:561
typename std::remove_reference< decltype(*std::begin(std::declval< RangeT & >()))>::type ValueOfRange
Definition: STLExtras.h:25
Definition: Location.h:126
intptr_t opaqueVal
Definition: Diagnostics.h:156
InFlightDiagnostic & operator<<(Arg &&arg) &
Stream operator for new diagnostic arguments.
Definition: Diagnostics.h:335
double doubleVal
Definition: Diagnostics.h:155
NoteIteratorImpl< NoteVector::const_iterator > const_note_iterator
Definition: Diagnostics.h:274
Definition: MLIRContext.h:34
void print(OpAsmPrinter &p, AffineIfOp op)
Definition: AffineOps.cpp:1671
InFlightDiagnostic & append(Args &&... args) &
Append arguments to the diagnostic.
Definition: Diagnostics.h:343
Definition: StandardTypes.h:63
Diagnostic & append(Arg &&arg)
Append one argument to the diagnostic.
Definition: Diagnostics.h:257
mlir::edsc::intrinsics::ValueBuilder< RangeOp > range
Definition: Intrinsics.h:23
ScopedDiagnosticHandler(MLIRContext *ctx, FuncTy &&handler)
Definition: Diagnostics.h:510
iterator_range< const_note_iterator > getNotes() const
Definition: Diagnostics.h:280
Definition: OperationSupport.h:203
double getAsDouble() const
Returns this argument as a double.
Definition: Diagnostics.h:76
Definition: Attributes.h:134