[Mlir-commits] [mlir] 7b5dfb4 - [mlir] Add support for diagnostics in C API.

Alex Zinenko llvmlistbot at llvm.org
Wed Oct 7 05:42:13 PDT 2020


Author: Alex Zinenko
Date: 2020-10-07T14:42:02+02:00
New Revision: 7b5dfb400a67f03122b43cd5d59b8b1ef6d00147

URL: https://github.com/llvm/llvm-project/commit/7b5dfb400a67f03122b43cd5d59b8b1ef6d00147
DIFF: https://github.com/llvm/llvm-project/commit/7b5dfb400a67f03122b43cd5d59b8b1ef6d00147.diff

LOG: [mlir] Add support for diagnostics in C API.

Add basic support for registering diagnostic handlers with the context
(actually, the diagnostic engine contained in the context) and processing
diagnostic messages from the C API.

Reviewed By: stellaraccident

Differential Revision: https://reviews.llvm.org/D88736

Added: 
    mlir/include/mlir-c/Diagnostics.h
    mlir/include/mlir/CAPI/Diagnostics.h
    mlir/lib/CAPI/IR/Diagnostics.cpp

Modified: 
    mlir/include/mlir-c/Support.h
    mlir/include/mlir/CAPI/Support.h
    mlir/lib/CAPI/IR/CMakeLists.txt
    mlir/test/CAPI/ir.c

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir-c/Diagnostics.h b/mlir/include/mlir-c/Diagnostics.h
new file mode 100644
index 000000000000..40ea6d8c405a
--- /dev/null
+++ b/mlir/include/mlir-c/Diagnostics.h
@@ -0,0 +1,87 @@
+/*===-- mlir-c/Diagnostics.h - MLIR Diagnostic subsystem C API ----*- 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 header declares the C APIs accessing MLIR Diagnostics subsystem.      *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef MLIR_C_DIAGNOSTICS_H
+#define MLIR_C_DIAGNOSTICS_H
+
+#include "mlir-c/IR.h"
+#include "mlir-c/Support.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** An opaque reference to a dignostic, always owned by the diagnostics engine
+ * (context). Must not be stored outside of the diagnostic handler. */
+struct MlirDiagnostic {
+  void *ptr;
+};
+typedef struct MlirDiagnostic MlirDiagnostic;
+
+/** Severity of a diagnostic. */
+enum MlirDiagnosticSeverity {
+  MlirDiagnosticError,
+  MlirDiagnosticWarning,
+  MlirDiagnosticNote,
+  MlirDiagnosticRemark
+};
+typedef enum MlirDiagnosticSeverity MlirDiagnosticSeverity;
+
+/** Opaque identifier of a diagnostic handler, useful to detach a handler. */
+typedef uint64_t MlirDiagnosticHandlerID;
+
+/** Diagnostic handler type. Acceps a reference to a diagnostic, which is only
+ * guaranteed to be live during the call. If the handler processed the
+ * diagnostic completely, it is expected to return success. Otherwise, it is
+ * expected to return failure to indicate that other handlers should attempt to
+ * process the diagnostic. */
+typedef MlirLogicalResult (*MlirDiagnosticHandler)(MlirDiagnostic);
+
+/** Prints a diagnostic using the provided callback. */
+void mlirDiagnosticPrint(MlirDiagnostic diagnostic, MlirStringCallback callback,
+                         void *userData);
+
+/** Returns the location at which the diagnostic is reported. */
+MlirLocation mlirDiagnosticGetLocation(MlirDiagnostic diagnostic);
+
+/** Returns the severity of the diagnostic. */
+MlirDiagnosticSeverity mlirDiagnosticGetSeverity(MlirDiagnostic diagnostic);
+
+/** Returns the number of notes attached to the diagnostic. */
+intptr_t mlirDiagnosticGetNumNotes(MlirDiagnostic diagnostic);
+
+/** Returns `pos`-th note attached to the diagnostic. Expects `pos` to be a
+ * valid zero-based index into the list of notes. */
+MlirDiagnostic mlirDiagnosticGetNote(MlirDiagnostic diagnostic, intptr_t pos);
+
+/** Attaches the diagnostic handler to the context. Handlers are invoked in the
+ * reverse order of attachment until one of them processes the diagnostic
+ * completely. Returns an identifier that can be used to detach the handler. */
+MlirDiagnosticHandlerID
+mlirContextAttachDiagnosticHandler(MlirContext context,
+                                   MlirDiagnosticHandler handler);
+
+/** Detaches an attached diagnostic handler from the context given its
+ * identifier. */
+void mlirContextDetachDiagnosticHandler(MlirContext context,
+                                        MlirDiagnosticHandlerID id);
+
+/** Emits an error at the given location through the diagnostics engine. Used
+ * for testing purposes. */
+void mlirEmitError(MlirLocation location, const char *message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MLIR_C_DIAGNOSTICS_H

diff  --git a/mlir/include/mlir-c/Support.h b/mlir/include/mlir-c/Support.h
index 1039c68c09bf..accf6cc0eab8 100644
--- a/mlir/include/mlir-c/Support.h
+++ b/mlir/include/mlir-c/Support.h
@@ -50,6 +50,42 @@ inline MlirStringRef mlirStringRefCreate(const char *str, size_t length) {
  */
 MlirStringRef mlirStringRefCreateFromCString(const char *str);
 
+/*============================================================================*/
+/* MlirLogicalResult.                                                         */
+/*============================================================================*/
+
+/** A logical result value, essentially a boolean with named states. LLVM
+ * convention for using boolean values to designate success or failure of an
+ * operation is a moving target, so MLIR opted for an explicit class.
+ * Instances of MlirLogicalResult must only be inspected using the associated
+ * functions. */
+struct MlirLogicalResult {
+  int8_t value;
+};
+typedef struct MlirLogicalResult MlirLogicalResult;
+
+/** Checks if the given logical result represents a success. */
+inline int mlirLogicalResultIsSuccess(MlirLogicalResult res) {
+  return res.value != 0;
+}
+
+/** Checks if the given logical result represents a failure. */
+inline int mlirLogicalResultIsFailure(MlirLogicalResult res) {
+  return res.value == 0;
+}
+
+/** Creates a logical result representing a success. */
+inline static MlirLogicalResult mlirLogicalResultSuccess() {
+  MlirLogicalResult res = {1};
+  return res;
+}
+
+/** Creates a logical result representing a failure. */
+inline static MlirLogicalResult mlirLogicalResultFailure() {
+  MlirLogicalResult res = {0};
+  return res;
+}
+
 #ifdef __cplusplus
 }
 #endif

diff  --git a/mlir/include/mlir/CAPI/Diagnostics.h b/mlir/include/mlir/CAPI/Diagnostics.h
new file mode 100644
index 000000000000..a632b9b99499
--- /dev/null
+++ b/mlir/include/mlir/CAPI/Diagnostics.h
@@ -0,0 +1,28 @@
+//===- IR.h - C API Utils for MLIR Diagnostics ------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CAPI_DIAGNOSTICS_H
+#define MLIR_CAPI_DIAGNOSTICS_H
+
+#include "mlir-c/Diagnostics.h"
+#include <cassert>
+
+namespace mlir {
+class Diagnostic;
+} // namespace mlir
+
+inline mlir::Diagnostic &unwrap(MlirDiagnostic diagnostic) {
+  assert(diagnostic.ptr && "unexpected null diagnostic");
+  return *(static_cast<mlir::Diagnostic *>(diagnostic.ptr));
+}
+
+inline MlirDiagnostic wrap(mlir::Diagnostic &diagnostic) {
+  return {&diagnostic};
+}
+
+#endif // MLIR_CAPI_DIAGNOSTICS_H

diff  --git a/mlir/include/mlir/CAPI/Support.h b/mlir/include/mlir/CAPI/Support.h
index 0c2b06990665..6d9a59abf111 100644
--- a/mlir/include/mlir/CAPI/Support.h
+++ b/mlir/include/mlir/CAPI/Support.h
@@ -16,6 +16,7 @@
 #define MLIR_CAPI_SUPPORT_H
 
 #include "mlir-c/Support.h"
+#include "mlir/Support/LogicalResult.h"
 #include "llvm/ADT/StringRef.h"
 
 /// Converts a StringRef into its MLIR C API equivalent.
@@ -28,4 +29,14 @@ inline llvm::StringRef unwrap(MlirStringRef ref) {
   return llvm::StringRef(ref.data, ref.length);
 }
 
+inline MlirLogicalResult wrap(mlir::LogicalResult res) {
+  if (mlir::succeeded(res))
+    return mlirLogicalResultSuccess();
+  return mlirLogicalResultFailure();
+}
+
+inline mlir::LogicalResult unwrap(MlirLogicalResult res) {
+  return mlir::success(mlirLogicalResultIsSuccess(res));
+}
+
 #endif // MLIR_CAPI_SUPPORT_H

diff  --git a/mlir/lib/CAPI/IR/CMakeLists.txt b/mlir/lib/CAPI/IR/CMakeLists.txt
index 4158a4c96efd..cf285fd06e60 100644
--- a/mlir/lib/CAPI/IR/CMakeLists.txt
+++ b/mlir/lib/CAPI/IR/CMakeLists.txt
@@ -1,6 +1,7 @@
 # Main API.
 add_mlir_library(MLIRCAPIIR
   AffineMap.cpp
+  Diagnostics.cpp
   IR.cpp
   StandardAttributes.cpp
   StandardTypes.cpp

diff  --git a/mlir/lib/CAPI/IR/Diagnostics.cpp b/mlir/lib/CAPI/IR/Diagnostics.cpp
new file mode 100644
index 000000000000..9595446f9d5a
--- /dev/null
+++ b/mlir/lib/CAPI/IR/Diagnostics.cpp
@@ -0,0 +1,75 @@
+//===- Diagnostics.cpp - C Interface for MLIR Diagnostics -----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir-c/Diagnostics.h"
+#include "mlir/CAPI/Diagnostics.h"
+#include "mlir/CAPI/IR.h"
+#include "mlir/CAPI/Support.h"
+#include "mlir/CAPI/Utils.h"
+#include "mlir/IR/Diagnostics.h"
+
+using namespace mlir;
+
+void mlirDiagnosticPrint(MlirDiagnostic diagnostic, MlirStringCallback callback,
+                         void *userData) {
+  detail::CallbackOstream stream(callback, userData);
+  unwrap(diagnostic).print(stream);
+  stream.flush();
+}
+
+MlirLocation mlirDiagnosticGetLocation(MlirDiagnostic diagnostic) {
+  return wrap(unwrap(diagnostic).getLocation());
+}
+
+MlirDiagnosticSeverity mlirDiagnosticGetSeverity(MlirDiagnostic diagnostic) {
+  switch (unwrap(diagnostic).getSeverity()) {
+  case mlir::DiagnosticSeverity::Error:
+    return MlirDiagnosticError;
+  case mlir::DiagnosticSeverity::Warning:
+    return MlirDiagnosticWarning;
+  case mlir::DiagnosticSeverity::Note:
+    return MlirDiagnosticNote;
+  case mlir::DiagnosticSeverity::Remark:
+    return MlirDiagnosticRemark;
+  }
+  llvm_unreachable("unhandled diagnostic severity");
+}
+
+// Notes are stored in a vector, so note iterator range is a pair of
+// random access iterators, for which it is cheap to compute the size.
+intptr_t mlirDiagnosticGetNumNotes(MlirDiagnostic diagnostic) {
+  return static_cast<intptr_t>(llvm::size(unwrap(diagnostic).getNotes()));
+}
+
+// Notes are stored in a vector, so the iterator is a random access iterator,
+// cheap to advance multiple steps at a time.
+MlirDiagnostic mlirDiagnosticGetNote(MlirDiagnostic diagnostic, intptr_t pos) {
+  return wrap(*std::next(unwrap(diagnostic).getNotes().begin(), pos));
+}
+
+MlirDiagnosticHandlerID
+mlirContextAttachDiagnosticHandler(MlirContext context,
+                                   MlirDiagnosticHandler handler) {
+  assert(handler && "unexpected null diagnostic handler");
+  DiagnosticEngine::HandlerID id =
+      unwrap(context)->getDiagEngine().registerHandler(
+          [handler](Diagnostic &diagnostic) {
+            return unwrap(handler(wrap(diagnostic)));
+          });
+  return static_cast<MlirDiagnosticHandlerID>(id);
+}
+
+void mlirContextDetachDiagnosticHandler(MlirContext context,
+                                        MlirDiagnosticHandlerID id) {
+  unwrap(context)->getDiagEngine().eraseHandler(
+      static_cast<DiagnosticEngine::HandlerID>(id));
+}
+
+void mlirEmitError(MlirLocation location, const char *message) {
+  emitError(unwrap(location)) << message;
+}

diff  --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index ae60d56a22ed..18c4e8b08559 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -10,8 +10,9 @@
 /* RUN: mlir-capi-ir-test 2>&1 | FileCheck %s
  */
 
-#include "mlir-c/IR.h"
 #include "mlir-c/AffineMap.h"
+#include "mlir-c/Diagnostics.h"
+#include "mlir-c/IR.h"
 #include "mlir-c/Registration.h"
 #include "mlir-c/StandardAttributes.h"
 #include "mlir-c/StandardDialect.h"
@@ -827,6 +828,28 @@ int registerOnlyStd() {
   return 0;
 }
 
+// Wraps a diagnostic into additional text we can match against.
+MlirLogicalResult errorHandler(MlirDiagnostic diagnostic) {
+  fprintf(stderr, "processing diagnostic <<\n");
+  mlirDiagnosticPrint(diagnostic, printToStderr, NULL);
+  fprintf(stderr, "\n");
+  MlirLocation loc = mlirDiagnosticGetLocation(diagnostic);
+  mlirLocationPrint(loc, printToStderr, NULL);
+  assert(mlirDiagnosticGetNumNotes(diagnostic) == 0);
+  fprintf(stderr, ">> end of diagnostic\n");
+  return mlirLogicalResultSuccess();
+}
+
+void testDiagnostics() {
+  MlirContext ctx = mlirContextCreate();
+  MlirDiagnosticHandlerID id =
+      mlirContextAttachDiagnosticHandler(ctx, errorHandler);
+  MlirLocation loc = mlirLocationUnknownGet(ctx);
+  mlirEmitError(loc, "test diagnostics");
+  mlirContextDetachDiagnosticHandler(ctx, id);
+  mlirEmitError(loc, "more test diagnostics");
+}
+
 int main() {
   MlirContext ctx = mlirContextCreate();
   mlirRegisterAllDialects(ctx);
@@ -982,5 +1005,16 @@ int main() {
 
   mlirContextDestroy(ctx);
 
+  fprintf(stderr, "@test_diagnostics\n");
+  testDiagnostics();
+  // clang-format off
+  // CHECK-LABEL: @test_diagnostics
+  // CHECK: processing diagnostic <<
+  // CHECK:   test diagnostics
+  // CHECK:   loc(unknown)
+  // CHECK: >> end of diagnostic
+  // CHECK-NOT: processing diagnostic
+  // CHECK:     more test diagnostics
+
   return 0;
 }


        


More information about the Mlir-commits mailing list