diff --git a/mlir/include/mlir/IR/Diagnostics.h b/mlir/include/mlir/IR/Diagnostics.h --- a/mlir/include/mlir/IR/Diagnostics.h +++ b/mlir/include/mlir/IR/Diagnostics.h @@ -42,6 +42,7 @@ Warning, Error, Remark, + Debugging, }; //===----------------------------------------------------------------------===// @@ -354,6 +355,11 @@ /// Abandons this diagnostic so that it will no longer be reported. void abandon(); + Diagnostic &getDiagnostic() { + assert(isActive() && "diagnostic not active"); + return impl.getValue(); + } + /// Allow an inflight diagnostic to be converted to 'failure', otherwise /// 'success' if this is an empty diagnostic. operator LogicalResult() const; @@ -418,6 +424,14 @@ /// this handler at a later time. HandlerID registerHandler(const HandlerTy &handler); + /// Register a handler to the engine to collect the diagnostic for debugging + /// purpose. The debugging diagnostic will be discarded if there's no + /// registered handler. + HandlerTy registerDebuggingHandler(const HandlerTy &handler); + + /// Return true if it has a registered debugging handler. + bool hasDebuggingHandler() const; + /// Set the diagnostic handler with a function that returns void. This is a /// convenient wrapper for handlers that always completely process the given /// diagnostic. @@ -434,6 +448,9 @@ /// Erase the registered diagnostic handler with the given identifier. void eraseHandler(HandlerID id); + /// Erase the registered debugging handler. + void eraseDebuggingHandler(); + /// Create a new inflight diagnostic with the given location and severity. InFlightDiagnostic emit(Location loc, DiagnosticSeverity severity) { assert(severity != DiagnosticSeverity::Note && @@ -465,6 +482,10 @@ InFlightDiagnostic emitRemark(Location loc); InFlightDiagnostic emitRemark(Location loc, const Twine &message); +/// Utility method to emit a debugging message using this location. +LogicalResult emitDebugging(Location loc, + function_ref reasonCallback); + /// Overloads of the above emission functions that take an optionally null /// location. If the location is null, no diagnostic is emitted and a failure is /// returned. Given that the provided location may be null, these methods take @@ -523,6 +544,34 @@ MLIRContext *ctx; }; +//===----------------------------------------------------------------------===// +// ScopedDebuggingHandler +//===----------------------------------------------------------------------===// + +class ScopedDebuggingHandler { +public: + explicit ScopedDebuggingHandler(MLIRContext *ctx) : ctx(ctx) {} + + template + ScopedDebuggingHandler(MLIRContext *ctx, FuncTy &&handler) : ctx(ctx) { + setHandler(std::forward(handler)); + } + ~ScopedDebuggingHandler(); + +protected: + template + void setHandler(FuncTy &&handler) { + auto &diagEngine = ctx->getDiagEngine(); + old = diagEngine.registerDebuggingHandler(std::forward(handler)); + } + +private: + DiagnosticEngine::HandlerTy old; + + /// The context to erase the handler from. + MLIRContext *ctx; +}; + //===----------------------------------------------------------------------===// // SourceMgrDiagnosticHandler //===----------------------------------------------------------------------===// diff --git a/mlir/lib/IR/Diagnostics.cpp b/mlir/lib/IR/Diagnostics.cpp --- a/mlir/lib/IR/Diagnostics.cpp +++ b/mlir/lib/IR/Diagnostics.cpp @@ -209,6 +209,10 @@ /// the default behavior if not. void emit(Diagnostic diag); + /// Emit a diagnostic using the registered debugging handler if present, or + /// it'll be discarded. + void emitDebugging(Diagnostic diag); + /// A mutex to ensure that diagnostics emission is thread-safe. llvm::sys::SmartMutex mutex; @@ -217,6 +221,9 @@ 2> handlers; + /// The handler to deal with debugging message. + DiagnosticEngine::HandlerTy debuggingHandler; + /// This is a unique identifier counter for diagnostic handlers in the /// context. This id starts at 1 to allow for 0 to be used as a sentinel. DiagnosticEngine::HandlerID uniqueHandlerId = 1; @@ -227,6 +234,11 @@ /// Emit a diagnostic using the registered issue handle if present, or with /// the default behavior if not. void DiagnosticEngineImpl::emit(Diagnostic diag) { + if (diag.getSeverity() == DiagnosticSeverity::Debugging) { + emitDebugging(std::move(diag)); + return; + } + llvm::sys::SmartScopedLock lock(mutex); // Try to process the given diagnostic on one of the registered handlers. @@ -250,6 +262,18 @@ os.flush(); } +/// Emit a debugging diagnostic using the debuggingHandler if present, or it'll +/// be dropped directly. +void DiagnosticEngineImpl::emitDebugging(Diagnostic diag) { + if (!debuggingHandler) + return; + + llvm::sys::SmartScopedLock lock(mutex); + // This is user registered debugging handler, it's supposed to return success + // and we have no knowledge what to do if it reuturns failure. + (void)debuggingHandler(diag); +} + //===----------------------------------------------------------------------===// // DiagnosticEngine //===----------------------------------------------------------------------===// @@ -267,12 +291,29 @@ return uniqueID; } +DiagnosticEngine::HandlerTy +DiagnosticEngine::registerDebuggingHandler(const HandlerTy &handler) { + llvm::sys::SmartScopedLock lock(impl->mutex); + HandlerTy old = impl->debuggingHandler; + impl->debuggingHandler = handler; + return old; +} + +bool DiagnosticEngine::hasDebuggingHandler() const { + return impl->debuggingHandler != nullptr; +} + /// Erase the registered diagnostic handler with the given identifier. void DiagnosticEngine::eraseHandler(HandlerID handlerID) { llvm::sys::SmartScopedLock lock(impl->mutex); impl->handlers.erase(handlerID); } +void DiagnosticEngine::eraseDebuggingHandler() { + llvm::sys::SmartScopedLock lock(impl->mutex); + impl->debuggingHandler = nullptr; +} + /// Emit a diagnostic using the registered issue handler if present, or with /// the default behavior if not. void DiagnosticEngine::emit(Diagnostic diag) { @@ -328,6 +369,17 @@ return emitDiag(loc, DiagnosticSeverity::Remark, message); } +/// Emit a debugging message using this location. +LogicalResult +mlir::emitDebugging(Location loc, + function_ref reasonCallback) { + if (!loc->getContext()->getDiagEngine().hasDebuggingHandler()) + return failure(); + reasonCallback( + emitDiag(loc, DiagnosticSeverity::Debugging, {}).getDiagnostic()); + return success(); +} + //===----------------------------------------------------------------------===// // ScopedDiagnosticHandler //===----------------------------------------------------------------------===// @@ -337,6 +389,13 @@ ctx->getDiagEngine().eraseHandler(handlerID); } +//===----------------------------------------------------------------------===// +// ScopedDebuggingHandler +//===----------------------------------------------------------------------===// +ScopedDebuggingHandler::~ScopedDebuggingHandler() { + ctx->getDiagEngine().registerDebuggingHandler(old); +} + //===----------------------------------------------------------------------===// // SourceMgrDiagnosticHandler //===----------------------------------------------------------------------===// @@ -414,6 +473,10 @@ return llvm::SourceMgr::DK_Error; case DiagnosticSeverity::Remark: return llvm::SourceMgr::DK_Remark; + case DiagnosticSeverity::Debugging: + // Debugging kind doesn't have equivalent type in SourceMgr and it's not to + // be here. + break; } llvm_unreachable("Unknown DiagnosticSeverity"); } @@ -622,6 +685,8 @@ return "error"; case DiagnosticSeverity::Remark: return "remark"; + case DiagnosticSeverity::Debugging: + return "debugging"; } llvm_unreachable("Unknown DiagnosticSeverity"); } @@ -925,6 +990,9 @@ case DiagnosticSeverity::Remark: os << "remark: "; break; + case DiagnosticSeverity::Debugging: + os << "debugging: "; + break; } os << diag << '\n'; }); diff --git a/mlir/lib/Transforms/Utils/DialectConversion.cpp b/mlir/lib/Transforms/Utils/DialectConversion.cpp --- a/mlir/lib/Transforms/Utils/DialectConversion.cpp +++ b/mlir/lib/Transforms/Utils/DialectConversion.cpp @@ -1295,6 +1295,8 @@ LogicalResult ConversionPatternRewriterImpl::notifyMatchFailure( Location loc, function_ref reasonCallback) { LLVM_DEBUG({ + // If it returns failure, it means there's no debugging handler registered. + (void)emitDebugging(loc, reasonCallback); Diagnostic diag(loc, DiagnosticSeverity::Remark); reasonCallback(diag); logger.startLine() << "** Failure : " << diag.str() << "\n";