diff --git a/mlir/include/mlir-c/Target/LLVMIR.h b/mlir/include/mlir-c/Target/LLVMIR.h new file mode 100644 index 0000000000000..effa74b905ce6 --- /dev/null +++ b/mlir/include/mlir-c/Target/LLVMIR.h @@ -0,0 +1,39 @@ +//===-- LLVMIR.h - C Interface for MLIR LLVMIR Target -------------*- 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 interface to target LLVMIR with MLIR. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_C_TARGET_LLVMIR_H +#define MLIR_C_TARGET_LLVMIR_H + +#include "mlir-c/IR.h" +#include "mlir-c/Support.h" +#include "llvm-c/Support.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Translate operation that satisfies LLVM dialect module requirements into an +/// LLVM IR module living in the given context. This translates operations from +/// any dilalect that has a registered implementation of +/// LLVMTranslationDialectInterface. +/// +/// \returns the generated LLVM IR Module from the translated MLIR module, it is +/// owned by the caller. +MLIR_CAPI_EXPORTED LLVMModuleRef +mlirTranslateModuleToLLVMIR(MlirOperation module, LLVMContextRef context); + +#ifdef __cplusplus +} +#endif + +#endif // MLIR_C_TARGET_LLVMIR_H diff --git a/mlir/lib/CAPI/CMakeLists.txt b/mlir/lib/CAPI/CMakeLists.txt index 707e78ac3d1ea..6c438508425b7 100644 --- a/mlir/lib/CAPI/CMakeLists.txt +++ b/mlir/lib/CAPI/CMakeLists.txt @@ -14,6 +14,7 @@ add_subdirectory(Interfaces) add_subdirectory(IR) add_subdirectory(RegisterEverything) add_subdirectory(Transforms) +add_subdirectory(Target) if(MLIR_ENABLE_EXECUTION_ENGINE) add_subdirectory(ExecutionEngine) @@ -36,4 +37,3 @@ if(MLIR_BUILD_MLIR_C_DYLIB) endif() endif() endif() - diff --git a/mlir/lib/CAPI/Target/CMakeLists.txt b/mlir/lib/CAPI/Target/CMakeLists.txt new file mode 100644 index 0000000000000..ce86fd3def964 --- /dev/null +++ b/mlir/lib/CAPI/Target/CMakeLists.txt @@ -0,0 +1,12 @@ +add_mlir_upstream_c_api_library(MLIRCAPITarget + LLVMIR.cpp + + LINK_COMPONENTS + Core + + LINK_LIBS PUBLIC + MLIRToLLVMIRTranslationRegistration + MLIRCAPIIR + MLIRLLVMToLLVMIRTranslation + MLIRSupport +) diff --git a/mlir/lib/CAPI/Target/LLVMIR.cpp b/mlir/lib/CAPI/Target/LLVMIR.cpp new file mode 100644 index 0000000000000..dc798372be746 --- /dev/null +++ b/mlir/lib/CAPI/Target/LLVMIR.cpp @@ -0,0 +1,36 @@ +//===-- LLVMIR.h - C Interface for MLIR LLVMIR Target ---------------------===// +// +// 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/Target/LLVMIR.h" +#include "llvm-c/Support.h" + +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include + +#include "mlir/CAPI/IR.h" +#include "mlir/CAPI/Support.h" +#include "mlir/CAPI/Wrap.h" +#include "mlir/Target/LLVMIR/ModuleTranslation.h" + +using namespace mlir; + +LLVMModuleRef mlirTranslateModuleToLLVMIR(MlirOperation module, + LLVMContextRef context) { + Operation *moduleOp = unwrap(module); + + llvm::LLVMContext *ctx = llvm::unwrap(context); + + std::unique_ptr llvmModule = + mlir::translateModuleToLLVMIR(moduleOp, *ctx); + + LLVMModuleRef moduleRef = llvm::wrap(llvmModule.release()); + + return moduleRef; +} diff --git a/mlir/test/CAPI/CMakeLists.txt b/mlir/test/CAPI/CMakeLists.txt index 16a3d0ed9c62f..1096a3b080664 100644 --- a/mlir/test/CAPI/CMakeLists.txt +++ b/mlir/test/CAPI/CMakeLists.txt @@ -85,3 +85,12 @@ _add_capi_test_executable(mlir-capi-transform-test MLIRCAPIRegisterEverything MLIRCAPITransformDialect ) + +_add_capi_test_executable(mlir-capi-translation-test + translation.c + LINK_LIBS PRIVATE + MLIRCAPIIR + MLIRCAPILLVM + MLIRCAPIRegisterEverything + MLIRCAPITarget +) diff --git a/mlir/test/CAPI/translation.c b/mlir/test/CAPI/translation.c new file mode 100644 index 0000000000000..5a555e492cf09 --- /dev/null +++ b/mlir/test/CAPI/translation.c @@ -0,0 +1,69 @@ +//===- translation.c - Test MLIR Target translations ----------------------===// +// +// 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-translation-test 2>&1 | FileCheck %s + +#include "llvm-c/Core.h" +#include "llvm-c/Support.h" +#include "llvm-c/Types.h" + +#include "mlir-c/BuiltinTypes.h" +#include "mlir-c/Dialect/LLVM.h" +#include "mlir-c/IR.h" +#include "mlir-c/RegisterEverything.h" +#include "mlir-c/Support.h" +#include "mlir-c/Target/LLVMIR.h" + +#include +#include +#include +#include +#include + +// CHECK-LABEL: testToLLVMIR() +static void testToLLVMIR(MlirContext ctx) { + fprintf(stderr, "testToLLVMIR()\n"); + LLVMContextRef llvmCtx = LLVMContextCreate(); + + const char *moduleString = "llvm.func @add(%arg0: i64, %arg1: i64) -> i64 { \ + %0 = llvm.add %arg0, %arg1 : i64 \ + llvm.return %0 : i64 \ + }"; + + mlirRegisterAllLLVMTranslations(ctx); + + MlirModule module = + mlirModuleCreateParse(ctx, mlirStringRefCreateFromCString(moduleString)); + + MlirOperation operation = mlirModuleGetOperation(module); + + LLVMModuleRef llvmModule = mlirTranslateModuleToLLVMIR(operation, llvmCtx); + + // clang-format off + // CHECK: declare ptr @malloc(i64 %{{.*}}) + // CHECK: declare void @free(ptr %{{.*}}) + // CHECK: define i64 @add(i64 %[[arg1:.*]], i64 %[[arg2:.*]]) { + // CHECK-NEXT: %[[arg3:.*]] = add i64 %[[arg1]], %[[arg2]] + // CHECK-NEXT: ret i64 %[[arg3]] + // CHECK-NEXT: } + // clang-format on + LLVMDumpModule(llvmModule); + + LLVMDisposeModule(llvmModule); + mlirModuleDestroy(module); +} + +int main(void) { + MlirContext ctx = mlirContextCreate(); + mlirDialectHandleRegisterDialect(mlirGetDialectHandle__llvm__(), ctx); + mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("llvm")); + testToLLVMIR(ctx); + mlirContextDestroy(ctx); + return 0; +} diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt index e4343095578c1..ccb4a98254cd5 100644 --- a/mlir/test/CMakeLists.txt +++ b/mlir/test/CMakeLists.txt @@ -45,10 +45,10 @@ if (MLIR_INCLUDE_INTEGRATION_TESTS) message(FATAL_ERROR "MLIR_INCLUDE_INTEGRATION_TESTS requires a native target") endif() - # When the Integration tests are requested via the MLIR_INCLUDE_INTEGRATION_TESTS - # configuration flag, we automatically include sm80 tests when build for - # cuSparse when the configuration flag MLIR_ENABLE_CUDA_CUSPARSE is set and - # include sm80 lt tests when the MLIR_ENABLE_CUDA_CUSPARSELT is set in + # When the Integration tests are requested via the MLIR_INCLUDE_INTEGRATION_TESTS + # configuration flag, we automatically include sm80 tests when build for + # cuSparse when the configuration flag MLIR_ENABLE_CUDA_CUSPARSE is set and + # include sm80 lt tests when the MLIR_ENABLE_CUDA_CUSPARSELT is set in # addition to those. if (MLIR_ENABLE_CUDA_CUSPARSE) set(MLIR_RUN_CUDA_SM80_TESTS ON) @@ -101,6 +101,7 @@ set(MLIR_TEST_DEPENDS mlir-capi-quant-test mlir-capi-sparse-tensor-test mlir-capi-transform-test + mlir-capi-translation-test mlir-linalg-ods-yaml-gen mlir-lsp-server mlir-pdll-lsp-server diff --git a/mlir/test/lit.cfg.py b/mlir/test/lit.cfg.py index 87bbe51e95d4c..17c29445ba82b 100644 --- a/mlir/test/lit.cfg.py +++ b/mlir/test/lit.cfg.py @@ -106,6 +106,7 @@ def add_runtime(name): "mlir-capi-quant-test", "mlir-capi-sparse-tensor-test", "mlir-capi-transform-test", + "mlir-capi-translation-test", "mlir-cpu-runner", add_runtime("mlir_runner_utils"), add_runtime("mlir_c_runner_utils"),