[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
This commit is contained in:
parent
6e6a5acf00
commit
7b5dfb400a
87
mlir/include/mlir-c/Diagnostics.h
Normal file
87
mlir/include/mlir-c/Diagnostics.h
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
28
mlir/include/mlir/CAPI/Diagnostics.h
Normal file
28
mlir/include/mlir/CAPI/Diagnostics.h
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# Main API.
|
||||
add_mlir_library(MLIRCAPIIR
|
||||
AffineMap.cpp
|
||||
Diagnostics.cpp
|
||||
IR.cpp
|
||||
StandardAttributes.cpp
|
||||
StandardTypes.cpp
|
||||
|
||||
75
mlir/lib/CAPI/IR/Diagnostics.cpp
Normal file
75
mlir/lib/CAPI/IR/Diagnostics.cpp
Normal file
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user