Skip to content

Commit

Permalink
Add C bindings for mlir::ExecutionEngine
Browse files Browse the repository at this point in the history
This adds minimalistic bindings for the execution engine, allowing to
invoke the JIT from the C API. This is still quite early and
experimental and shouldn't be considered stable in any way.

Differential Revision: https://reviews.llvm.org/D96651
  • Loading branch information
joker-eph committed Mar 3, 2021
1 parent 55356c0 commit 86c8a78
Show file tree
Hide file tree
Showing 14 changed files with 304 additions and 1 deletion.
22 changes: 22 additions & 0 deletions mlir/include/mlir-c/Conversion.h
@@ -0,0 +1,22 @@
//===-- mlir-c/Conversion.h - Conversion passes initialization ----*- 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 registration and creation method for conversion
// passes.
//
//===----------------------------------------------------------------------===//

#ifndef MLIR_C_CONVERSIONS_H
#define MLIR_C_CONVERSIONS_H

#include "mlir-c/Support.h"

#include "mlir/Conversion/Passes.capi.h.inc"

#endif // MLIR_C_CONVERSIONS_H
63 changes: 63 additions & 0 deletions mlir/include/mlir-c/ExecutionEngine.h
@@ -0,0 +1,63 @@
//===-- mlir-c/ExecutionEngine.h - Execution engine management ---*- 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 provides basic access to the MLIR JIT. This is minimalist and
// experimental at the moment.
//
//===----------------------------------------------------------------------===//

#ifndef MLIR_C_EXECUTIONENGINE_H
#define MLIR_C_EXECUTIONENGINE_H

#include "mlir-c/IR.h"
#include "mlir-c/Support.h"

#ifdef __cplusplus
extern "C" {
#endif

#define DEFINE_C_API_STRUCT(name, storage) \
struct name { \
storage *ptr; \
}; \
typedef struct name name

DEFINE_C_API_STRUCT(MlirExecutionEngine, void);

#undef DEFINE_C_API_STRUCT

/// Creates an ExecutionEngine for the provided ModuleOp. The ModuleOp is
/// expected to be "translatable" to LLVM IR (only contains operations in
/// dialects that implement the `LLVMTranslationDialectInterface`). The module
/// ownership stays with the client and can be destroyed as soon as the call
/// returns.
/// TODO: figure out options (optimization level, etc.).
MLIR_CAPI_EXPORTED MlirExecutionEngine mlirExecutionEngineCreate(MlirModule op);

/// Destroy an ExecutionEngine instance.
MLIR_CAPI_EXPORTED void mlirExecutionEngineDestroy(MlirExecutionEngine jit);

/// Checks whether an execution engine is null.
static inline bool mlirExecutionEngineIsNull(MlirExecutionEngine jit) {
return !jit.ptr;
}

/// Invoke a native function in the execution engine by name with the arguments
/// and result of the invoked function passed as an array of pointers. The
/// function must have been tagged with the `llvm.emit_c_interface` attribute.
/// Returns a failure if the execution fails for any reason (the function name
/// can't be resolved for instance).
MLIR_CAPI_EXPORTED MlirLogicalResult mlirExecutionEngineInvokePacked(
MlirExecutionEngine jit, MlirStringRef name, void **arguments);

#ifdef __cplusplus
}
#endif

#endif // EXECUTIONENGINE_H
3 changes: 3 additions & 0 deletions mlir/include/mlir-c/Registration.h
Expand Up @@ -57,6 +57,9 @@ MLIR_CAPI_EXPORTED MlirDialect mlirDialectHandleLoadDialect(MlirDialectHandle,
/// TODO: Remove this function once the real registration API is finished.
MLIR_CAPI_EXPORTED void mlirRegisterAllDialects(MlirContext context);

/// Register all translations to LLVM IR for dialects that can support it.
MLIR_CAPI_EXPORTED void mlirRegisterAllLLVMTranslations(MlirContext context);

#ifdef __cplusplus
}
#endif
Expand Down
24 changes: 24 additions & 0 deletions mlir/include/mlir/CAPI/ExecutionEngine.h
@@ -0,0 +1,24 @@
//===- IR.h - C API Utils for Core MLIR classes -----------------*- 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 file contains declarations of implementation details of the C API for
// core MLIR classes. This file should not be included from C++ code other than
// C API implementation nor from C code.
//
//===----------------------------------------------------------------------===//

#ifndef MLIR_CAPI_EXECUTIONENGINE_H
#define MLIR_CAPI_EXECUTIONENGINE_H

#include "mlir-c/ExecutionEngine.h"
#include "mlir/CAPI/Wrap.h"
#include "mlir/ExecutionEngine/ExecutionEngine.h"

DEFINE_C_API_PTR_METHODS(MlirExecutionEngine, mlir::ExecutionEngine)

#endif // MLIR_CAPI_EXECUTIONENGINE_H
2 changes: 2 additions & 0 deletions mlir/include/mlir/Conversion/CMakeLists.txt
@@ -1,6 +1,8 @@

set(LLVM_TARGET_DEFINITIONS Passes.td)
mlir_tablegen(Passes.h.inc -gen-pass-decls -name Conversion)
mlir_tablegen(Passes.capi.h.inc -gen-pass-capi-header --prefix Conversion)
mlir_tablegen(Passes.capi.cpp.inc -gen-pass-capi-impl --prefix Conversion)
add_public_tablegen_target(MLIRConversionPassIncGen)

add_mlir_doc(Passes -gen-pass-doc ConversionPasses ./)
4 changes: 3 additions & 1 deletion mlir/lib/CAPI/CMakeLists.txt
@@ -1,6 +1,8 @@
add_subdirectory(Dialect)
add_subdirectory(Conversion)
add_subdirectory(ExecutionEngine)
add_subdirectory(IR)
add_subdirectory(Registration)
add_subdirectory(Dialect)
add_subdirectory(Transforms)


Expand Down
7 changes: 7 additions & 0 deletions mlir/lib/CAPI/Conversion/CMakeLists.txt
@@ -0,0 +1,7 @@
get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS)
add_mlir_public_c_api_library(MLIRCAPIConversion
Passes.cpp

LINK_LIBS PUBLIC
${conversion_libs}
)
26 changes: 26 additions & 0 deletions mlir/lib/CAPI/Conversion/Passes.cpp
@@ -0,0 +1,26 @@
//===- Conversion.cpp - C API for Conversion Passes -----------------------===//
//
// 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/Conversion/Passes.h"
#include "mlir/CAPI/Pass.h"
#include "mlir/Pass/Pass.h"

// Must include the declarations as they carry important visibility attributes.
#include "mlir/Conversion/Passes.capi.h.inc"

using namespace mlir;

#ifdef __cplusplus
extern "C" {
#endif

#include "mlir/Conversion/Passes.capi.cpp.inc"

#ifdef __cplusplus
}
#endif
7 changes: 7 additions & 0 deletions mlir/lib/CAPI/ExecutionEngine/CMakeLists.txt
@@ -0,0 +1,7 @@
# Main API shared library.
add_mlir_public_c_api_library(MLIRCEXECUTIONENGINE
ExecutionEngine.cpp

LINK_LIBS PUBLIC
MLIRExecutionEngine
)
46 changes: 46 additions & 0 deletions mlir/lib/CAPI/ExecutionEngine/ExecutionEngine.cpp
@@ -0,0 +1,46 @@
//===- ExecutionEngine.cpp - C API for MLIR JIT ---------------------------===//
//
// 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/ExecutionEngine.h"
#include "mlir/CAPI/ExecutionEngine.h"
#include "mlir/CAPI/IR.h"
#include "mlir/CAPI/Support.h"
#include "llvm/Support/TargetSelect.h"

using namespace mlir;

extern "C" MlirExecutionEngine mlirExecutionEngineCreate(MlirModule op) {
static bool init_once = [] {
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
return true;
}();
(void)init_once;

auto jitOrError = ExecutionEngine::create(unwrap(op));
if (!jitOrError) {
consumeError(jitOrError.takeError());
return MlirExecutionEngine{nullptr};
}
return wrap(jitOrError->release());
}

extern "C" void mlirExecutionEngineDestroy(MlirExecutionEngine jit) {
delete (unwrap(jit));
}

extern "C" MlirLogicalResult
mlirExecutionEngineInvokePacked(MlirExecutionEngine jit, MlirStringRef name,
void **arguments) {
const std::string ifaceName = ("_mlir_ciface_" + unwrap(name)).str();
llvm::Error error = unwrap(jit)->invokePacked(
ifaceName, MutableArrayRef<void *>{arguments, (size_t)0});
if (error)
return wrap(failure());
return wrap(success());
}
5 changes: 5 additions & 0 deletions mlir/lib/CAPI/Registration/Registration.cpp
Expand Up @@ -10,9 +10,14 @@

#include "mlir/CAPI/IR.h"
#include "mlir/InitAllDialects.h"
#include "mlir/Target/LLVMIR.h"

void mlirRegisterAllDialects(MlirContext context) {
mlir::registerAllDialects(*unwrap(context));
// TODO: we may not want to eagerly load here.
unwrap(context)->loadAllAvailableDialects();
}

void mlirRegisterAllLLVMTranslations(MlirContext context) {
mlir::registerLLVMDialectTranslation(*unwrap(context));
}
14 changes: 14 additions & 0 deletions mlir/test/CAPI/CMakeLists.txt
@@ -1,4 +1,5 @@
set(LLVM_OPTIONAL_SOURCES
execution_engine.c
ir.c
pass.c
)
Expand Down Expand Up @@ -28,3 +29,16 @@ target_link_libraries(mlir-capi-pass-test
PRIVATE
MLIRPublicAPI
)

add_llvm_executable(mlir-capi-execution-engine-test
execution_engine.c
DEPENDS
MLIRConversionPassIncGen
)
llvm_update_compile_flags(mlir-capi-execution-engine-test)

get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
target_link_libraries(mlir-capi-execution-engine-test
PRIVATE
MLIRPublicAPI
)
81 changes: 81 additions & 0 deletions mlir/test/CAPI/execution_engine.c
@@ -0,0 +1,81 @@
//===- execution_engine.c - Test for the C bindings for the MLIR JIT-------===//
//
// 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
//
//===----------------------------------------------------------------------===//

/* RUN: mlir-capi-execution-engine-test 2>&1 | FileCheck %s
*/

#include "mlir-c/Conversion.h"
#include "mlir-c/ExecutionEngine.h"
#include "mlir-c/IR.h"
#include "mlir-c/Registration.h"

#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void lowerModuleToLLVM(MlirContext ctx, MlirModule module) {
MlirPassManager pm = mlirPassManagerCreate(ctx);
mlirPassManagerAddOwnedPass(pm, mlirCreateConversionConvertStandardToLLVM());
MlirLogicalResult status = mlirPassManagerRun(pm, module);
if (mlirLogicalResultIsFailure(status)) {
fprintf(stderr, "Unexpected failure running pass pipeline\n");
exit(2);
}
mlirPassManagerDestroy(pm);
}

// CHECK-LABEL: Running test 'testSimpleExecution'
void testSimpleExecution() {
MlirContext ctx = mlirContextCreate();
mlirRegisterAllDialects(ctx);
MlirModule module = mlirModuleCreateParse(
ctx, mlirStringRefCreateFromCString(
// clang-format off
"module { \n"
" func @add(%arg0 : i32) -> i32 attributes { llvm.emit_c_interface } { \n"
" %res = std.addi %arg0, %arg0 : i32 \n"
" return %res : i32 \n"
" } \n"
"}"));
// clang-format on
lowerModuleToLLVM(ctx, module);
mlirRegisterAllLLVMTranslations(ctx);
MlirExecutionEngine jit = mlirExecutionEngineCreate(module);
if (mlirExecutionEngineIsNull(jit)) {
fprintf(stderr, "Execution engine creation failed");
exit(2);
}
int input = 42;
int result = -1;
void *args[2] = {&input, &result};
if (mlirLogicalResultIsFailure(mlirExecutionEngineInvokePacked(
jit, mlirStringRefCreateFromCString("add"), args))) {
fprintf(stderr, "Execution engine creation failed");
abort();
}
// CHECK: Input: 42 Result: 84
printf("Input: %d Result: %d\n", input, result);
mlirExecutionEngineDestroy(jit);
mlirModuleDestroy(module);
mlirContextDestroy(ctx);
}

int main() {

#define _STRINGIFY(x) #x
#define STRINGIFY(x) _STRINGIFY(x)
#define TEST(test) \
printf("Running test '" STRINGIFY(test) "'\n"); \
test();

TEST(testSimpleExecution);
return 0;
}
1 change: 1 addition & 0 deletions mlir/test/CMakeLists.txt
Expand Up @@ -54,6 +54,7 @@ configure_lit_site_cfg(

set(MLIR_TEST_DEPENDS
FileCheck count not
mlir-capi-execution-engine-test
mlir-capi-ir-test
mlir-capi-pass-test
mlir-cpu-runner
Expand Down

0 comments on commit 86c8a78

Please sign in to comment.