[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