1//===- execution_engine.c - Test for the C bindings for the MLIR JIT-------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM
4// Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10/* RUN: mlir-capi-execution-engine-test 2>&1 | FileCheck %s
11 */
12/* REQUIRES: host-supports-jit
13 */
14
15#include "mlir-c/Conversion.h"
16#include "mlir-c/ExecutionEngine.h"
17#include "mlir-c/IR.h"
18#include "mlir-c/RegisterEverything.h"
19
20#include <assert.h>
21#include <math.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26static void registerAllUpstreamDialects(MlirContext ctx) {
27 MlirDialectRegistry registry = mlirDialectRegistryCreate();
28 mlirRegisterAllDialects(registry);
29 mlirContextAppendDialectRegistry(ctx, registry);
30 mlirDialectRegistryDestroy(registry);
31}
32
33void lowerModuleToLLVM(MlirContext ctx, MlirModule module) {
34 MlirPassManager pm = mlirPassManagerCreate(ctx);
35 MlirOpPassManager opm = mlirPassManagerGetNestedUnder(
36 pm, mlirStringRefCreateFromCString("func.func"));
37 mlirPassManagerAddOwnedPass(pm, mlirCreateConversionConvertFuncToLLVMPass());
38 mlirOpPassManagerAddOwnedPass(
39 opm, mlirCreateConversionArithToLLVMConversionPass());
40 MlirLogicalResult status =
41 mlirPassManagerRunOnOp(pm, mlirModuleGetOperation(module));
42 if (mlirLogicalResultIsFailure(res: status)) {
43 fprintf(stderr, format: "Unexpected failure running pass pipeline\n");
44 exit(status: 2);
45 }
46 mlirPassManagerDestroy(pm);
47}
48
49// CHECK-LABEL: Running test 'testSimpleExecution'
50void testSimpleExecution(void) {
51 MlirContext ctx = mlirContextCreate();
52 registerAllUpstreamDialects(ctx);
53
54 MlirModule module = mlirModuleCreateParse(
55 context: ctx, module: mlirStringRefCreateFromCString(
56 // clang-format off
57str: "module { \n"
58" func.func @add(%arg0 : i32) -> i32 attributes { llvm.emit_c_interface } { \n"
59" %res = arith.addi %arg0, %arg0 : i32 \n"
60" return %res : i32 \n"
61" } \n"
62"}"));
63 // clang-format on
64 lowerModuleToLLVM(ctx, module);
65 mlirRegisterAllLLVMTranslations(context: ctx);
66 MlirExecutionEngine jit = mlirExecutionEngineCreate(
67 op: module, /*optLevel=*/2, /*numPaths=*/0, /*sharedLibPaths=*/NULL,
68 /*enableObjectDump=*/false);
69 if (mlirExecutionEngineIsNull(jit)) {
70 fprintf(stderr, format: "Execution engine creation failed");
71 exit(status: 2);
72 }
73 int input = 42;
74 int result = -1;
75 void *args[2] = {&input, &result};
76 if (mlirLogicalResultIsFailure(res: mlirExecutionEngineInvokePacked(
77 jit, name: mlirStringRefCreateFromCString(str: "add"), arguments: args))) {
78 fprintf(stderr, format: "Execution engine creation failed");
79 abort();
80 }
81 // CHECK: Input: 42 Result: 84
82 printf(format: "Input: %d Result: %d\n", input, result);
83 mlirExecutionEngineDestroy(jit);
84 mlirModuleDestroy(module);
85 mlirContextDestroy(context: ctx);
86}
87
88// CHECK-LABEL: Running test 'testOmpCreation'
89void testOmpCreation(void) {
90 MlirContext ctx = mlirContextCreate();
91 registerAllUpstreamDialects(ctx);
92
93 MlirModule module = mlirModuleCreateParse(
94 context: ctx, module: mlirStringRefCreateFromCString(
95 // clang-format off
96str: "module { \n"
97" func.func @main() attributes { llvm.emit_c_interface } { \n"
98" %0 = arith.constant 0 : i32 \n"
99" %1 = arith.constant 1 : i32 \n"
100" %2 = arith.constant 2 : i32 \n"
101" omp.parallel { \n"
102" omp.wsloop { \n"
103" omp.loop_nest (%3) : i32 = (%0) to (%2) step (%1) { \n"
104" omp.yield \n"
105" } \n"
106" omp.terminator \n"
107" } \n"
108" omp.terminator \n"
109" } \n"
110" llvm.return \n"
111" } \n"
112"} \n"
113 ));
114 // clang-format on
115 lowerModuleToLLVM(ctx, module);
116
117 // At this point all operations in the MLIR module have been lowered to the
118 // 'llvm' dialect except 'omp' operations. The goal of this test is
119 // guaranteeing that the execution engine C binding has registered OpenMP
120 // translations and therefore does not fail when it encounters 'omp' ops.
121 // We don't attempt to run the engine, since that would force us to link
122 // against the OpenMP library.
123 MlirExecutionEngine jit = mlirExecutionEngineCreate(
124 op: module, /*optLevel=*/2, /*numPaths=*/0, /*sharedLibPaths=*/NULL,
125 /*enableObjectDump=*/false);
126 if (mlirExecutionEngineIsNull(jit)) {
127 fprintf(stderr, format: "Engine creation failed with OpenMP");
128 exit(status: 2);
129 }
130 // CHECK: Engine creation succeeded with OpenMP
131 printf(format: "Engine creation succeeded with OpenMP\n");
132 mlirExecutionEngineDestroy(jit);
133 mlirModuleDestroy(module);
134 mlirContextDestroy(context: ctx);
135}
136
137int main(void) {
138
139#define _STRINGIFY(x) #x
140#define STRINGIFY(x) _STRINGIFY(x)
141#define TEST(test) \
142 printf("Running test '" STRINGIFY(test) "'\n"); \
143 test();
144
145 TEST(testSimpleExecution);
146 TEST(testOmpCreation);
147 return 0;
148}
149

source code of mlir/test/CAPI/execution_engine.c