diff --git a/mlir/docs/SPIRVToLLVMDialectConversion.md b/mlir/docs/SPIRVToLLVMDialectConversion.md index 0aae02cff26be..872690bb52646 100644 --- a/mlir/docs/SPIRVToLLVMDialectConversion.md +++ b/mlir/docs/SPIRVToLLVMDialectConversion.md @@ -501,7 +501,7 @@ The SPIR-V to LLVM conversion does not involve modelling of workgroups. Hence, we say that only current invocation is in conversion's scope. This means that global variables with pointers of `Input`, `Output`, and `Private` storage classes are supported. Also, `StorageBuffer` storage class is allowed for -executing [`mlir-spirv-cpu-runner`](#mlir-spirv-cpu-runner). +executing [SPIR-V CPU Runner tests](#spir-v-cpu-runner-tests). Moreover, `bind` that specifies the descriptor set and the binding number and `built_in` that specifies SPIR-V `BuiltIn` decoration have no conversion into @@ -815,14 +815,15 @@ Module in SPIR-V has one region that contains one block. It is defined via `spirv.module` is converted into `ModuleOp`. This plays a role of enclosing scope to LLVM ops. At the moment, SPIR-V module attributes are ignored. -## `mlir-spirv-cpu-runner` +## SPIR-V CPU Runner Tests -`mlir-spirv-cpu-runner` allows to execute `gpu` dialect kernel on the CPU via -SPIR-V to LLVM dialect conversion. Currently, only single-threaded kernel is -supported. +The `mlir-cpu-runner` has support for executing a `gpu` dialect kernel on the +CPU via SPIR-V to LLVM dialect conversion. This is referred to as the "SPIR-V +CPU Runner". The `--link-nested-modules` flag needs to be passed for this. +Currently, only single-threaded kernels are supported. -To build the runner, add the following option to `cmake`: `bash --DMLIR_ENABLE_SPIRV_CPU_RUNNER=1` +To build the required runtime libaries, add the following option to `cmake`: +`-DMLIR_ENABLE_SPIRV_CPU_RUNNER=1` ### Pipeline @@ -846,7 +847,7 @@ executed using `ExecutionEngine`. ### Walk-through This section gives a detailed overview of the IR changes while running -`mlir-spirv-cpu-runner`. First, consider that we have the following IR. (For +SPIR-V CPU Runner tests. First, consider that we have the following IR. (For simplicity some type annotations and function implementations have been omitted). diff --git a/mlir/lib/ExecutionEngine/CMakeLists.txt b/mlir/lib/ExecutionEngine/CMakeLists.txt index 7fc17b97f0c56..cf44a02cf5cb9 100644 --- a/mlir/lib/ExecutionEngine/CMakeLists.txt +++ b/mlir/lib/ExecutionEngine/CMakeLists.txt @@ -14,6 +14,7 @@ set(LLVM_OPTIONAL_SOURCES RunnerUtils.cpp OptUtils.cpp JitRunner.cpp + SpirvCpuRuntimeWrappers.cpp SyclRuntimeWrappers.cpp ) @@ -401,4 +402,17 @@ if(LLVM_ENABLE_PIC) set_property(TARGET mlir_sycl_runtime APPEND PROPERTY BUILD_RPATH "${LevelZero_LIBRARIES_DIR}" "${SyclRuntime_LIBRARIES_DIR}") endif() + + if(MLIR_ENABLE_SPIRV_CPU_RUNNER) + add_mlir_library(mlir_spirv_cpu_runtime + SHARED + SpirvCpuRuntimeWrappers.cpp + + EXCLUDE_FROM_LIBMLIR + ) + + target_compile_definitions(mlir_spirv_cpu_runtime + PRIVATE + mlir_spirv_cpu_runtime_EXPORTS) + endif() endif() diff --git a/mlir/test/mlir-spirv-cpu-runner/mlir_test_spirv_cpu_runner_c_wrappers.cpp b/mlir/lib/ExecutionEngine/SpirvCpuRuntimeWrappers.cpp similarity index 94% rename from mlir/test/mlir-spirv-cpu-runner/mlir_test_spirv_cpu_runner_c_wrappers.cpp rename to mlir/lib/ExecutionEngine/SpirvCpuRuntimeWrappers.cpp index 93433be2dd66a..e6594df3b1ee7 100644 --- a/mlir/test/mlir-spirv-cpu-runner/mlir_test_spirv_cpu_runner_c_wrappers.cpp +++ b/mlir/lib/ExecutionEngine/SpirvCpuRuntimeWrappers.cpp @@ -1,4 +1,4 @@ -//===- mlir_test_spirv_cpu_runner_c_wrappers.cpp - Runner testing library -===// +//===- SpirvCpuRuntimeWrappers.cpp - Runner testing library -===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt index 361981605a76b..f181a91328f3f 100644 --- a/mlir/test/CMakeLists.txt +++ b/mlir/test/CMakeLists.txt @@ -197,10 +197,8 @@ if(LLVM_BUILD_EXAMPLES) endif() if(MLIR_ENABLE_SPIRV_CPU_RUNNER) - add_subdirectory(mlir-spirv-cpu-runner) list(APPEND MLIR_TEST_DEPENDS - mlir-spirv-cpu-runner - mlir_test_spirv_cpu_runner_c_wrappers + mlir_spirv_cpu_runtime ) endif() diff --git a/mlir/test/mlir-spirv-cpu-runner/double.mlir b/mlir/test/Integration/GPU/SPIRV/double.mlir similarity index 94% rename from mlir/test/mlir-spirv-cpu-runner/double.mlir rename to mlir/test/Integration/GPU/SPIRV/double.mlir index 35557ba1e94c0..b6887c26ebe0a 100644 --- a/mlir/test/mlir-spirv-cpu-runner/double.mlir +++ b/mlir/test/Integration/GPU/SPIRV/double.mlir @@ -1,5 +1,5 @@ // RUN: mlir-opt %s -test-spirv-cpu-runner-pipeline \ -// RUN: | mlir-spirv-cpu-runner - -e main --entry-point-result=void --shared-libs=%mlir_runner_utils,%mlir_test_spirv_cpu_runner_c_wrappers \ +// RUN: | mlir-cpu-runner - -e main --entry-point-result=void --shared-libs=%mlir_runner_utils,%mlir_spirv_cpu_runtime --link-nested-modules \ // RUN: | FileCheck %s // CHECK: [8, 8, 8, 8, 8, 8] diff --git a/mlir/test/mlir-spirv-cpu-runner/lit.local.cfg b/mlir/test/Integration/GPU/SPIRV/lit.local.cfg similarity index 100% rename from mlir/test/mlir-spirv-cpu-runner/lit.local.cfg rename to mlir/test/Integration/GPU/SPIRV/lit.local.cfg diff --git a/mlir/test/mlir-spirv-cpu-runner/simple_add.mlir b/mlir/test/Integration/GPU/SPIRV/simple_add.mlir similarity index 95% rename from mlir/test/mlir-spirv-cpu-runner/simple_add.mlir rename to mlir/test/Integration/GPU/SPIRV/simple_add.mlir index 75675a69a6758..0049ce60c4ebb 100644 --- a/mlir/test/mlir-spirv-cpu-runner/simple_add.mlir +++ b/mlir/test/Integration/GPU/SPIRV/simple_add.mlir @@ -1,5 +1,5 @@ // RUN: mlir-opt %s -test-spirv-cpu-runner-pipeline \ -// RUN: | mlir-spirv-cpu-runner - -e main --entry-point-result=void --shared-libs=%mlir_runner_utils,%mlir_test_spirv_cpu_runner_c_wrappers \ +// RUN: | mlir-cpu-runner - -e main --entry-point-result=void --shared-libs=%mlir_runner_utils,%mlir_spirv_cpu_runtime --link-nested-modules \ // RUN: | FileCheck %s // CHECK: data = diff --git a/mlir/test/lib/Pass/TestSPIRVCPURunnerPipeline.cpp b/mlir/test/lib/Pass/TestSPIRVCPURunnerPipeline.cpp index ded0d22c31307..bf2880aa022ee 100644 --- a/mlir/test/lib/Pass/TestSPIRVCPURunnerPipeline.cpp +++ b/mlir/test/lib/Pass/TestSPIRVCPURunnerPipeline.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// Implements a pipeline for use by mlir-spirv-cpu-runner tests. +// Implements a pipeline for use by SPIR-V CPU Runner tests. // //===----------------------------------------------------------------------===// @@ -40,7 +40,7 @@ void registerTestSPIRVCPURunnerPipeline() { PassPipelineRegistration<>( "test-spirv-cpu-runner-pipeline", "Runs a series of passes for lowering SPIR-V-dialect MLIR to " - "LLVM-dialect MLIR intended for mlir-spirv-cpu-runner.", + "LLVM-dialect MLIR intended for SPIR-V CPU Runner tests.", buildTestSPIRVCPURunnerPipeline); } } // namespace test diff --git a/mlir/test/lit.cfg.py b/mlir/test/lit.cfg.py index f0d4f35ba3e22..9b429b424d357 100644 --- a/mlir/test/lit.cfg.py +++ b/mlir/test/lit.cfg.py @@ -125,11 +125,6 @@ def add_runtime(name): "not", ] -if config.enable_spirv_cpu_runner: - tools.extend( - ["mlir-spirv-cpu-runner", add_runtime("mlir_test_spirv_cpu_runner_c_wrappers")] - ) - if config.enable_vulkan_runner: tools.extend([add_runtime("vulkan-runtime-wrappers")]) @@ -142,6 +137,9 @@ def add_runtime(name): if config.enable_sycl_runner: tools.extend([add_runtime("mlir_sycl_runtime")]) +if config.enable_spirv_cpu_runner: + tools.extend([add_runtime("mlir_spirv_cpu_runtime")]) + if config.mlir_run_arm_sve_tests or config.mlir_run_arm_sme_tests: tools.extend([add_runtime("mlir_arm_runner_utils")]) diff --git a/mlir/test/mlir-spirv-cpu-runner/CMakeLists.txt b/mlir/test/mlir-spirv-cpu-runner/CMakeLists.txt deleted file mode 100644 index c7521db57a38e..0000000000000 --- a/mlir/test/mlir-spirv-cpu-runner/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set(LLVM_OPTIONAL_SOURCES - mlir_test_spirv_cpu_runner_c_wrappers.cpp - ) - -add_llvm_library(mlir_test_spirv_cpu_runner_c_wrappers SHARED mlir_test_spirv_cpu_runner_c_wrappers.cpp) -target_compile_definitions(mlir_test_spirv_cpu_runner_c_wrappers PRIVATE mlir_test_spirv_cpu_runner_c_wrappers_EXPORTS) diff --git a/mlir/tools/CMakeLists.txt b/mlir/tools/CMakeLists.txt index 0a2d0ff291509..072e83c5d45ea 100644 --- a/mlir/tools/CMakeLists.txt +++ b/mlir/tools/CMakeLists.txt @@ -6,7 +6,6 @@ add_subdirectory(mlir-query) add_subdirectory(mlir-reduce) add_subdirectory(mlir-rewrite) add_subdirectory(mlir-shlib) -add_subdirectory(mlir-spirv-cpu-runner) add_subdirectory(mlir-translate) add_subdirectory(mlir-vulkan-runner) add_subdirectory(tblgen-lsp-server) diff --git a/mlir/tools/mlir-cpu-runner/mlir-cpu-runner.cpp b/mlir/tools/mlir-cpu-runner/mlir-cpu-runner.cpp index 1b1d5d03d2be5..e018b63b43ad0 100644 --- a/mlir/tools/mlir-cpu-runner/mlir-cpu-runner.cpp +++ b/mlir/tools/mlir-cpu-runner/mlir-cpu-runner.cpp @@ -17,10 +17,68 @@ #include "mlir/ExecutionEngine/OptUtils.h" #include "mlir/IR/Dialect.h" #include "mlir/Target/LLVMIR/Dialect/All.h" +#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" +#include "mlir/Target/LLVMIR/Export.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Linker/Linker.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/TargetSelect.h" +using namespace mlir; + +// TODO: Consider removing this linking functionality from the SPIR-V CPU Runner +// flow in favour of a more proper host/device split like other runners. +// https://github.com/llvm/llvm-project/issues/115348 +llvm::cl::opt LinkNestedModules( + "link-nested-modules", + llvm::cl::desc("Link two nested MLIR modules into a single LLVM IR module. " + "Useful if both the host and device code can be run on the " + "same CPU, as in SPIR-V CPU Runner tests.")); + +/// A utility function that builds llvm::Module from two nested MLIR modules. +/// +/// module @main { +/// module @kernel { +/// // Some ops +/// } +/// // Some other ops +/// } +/// +/// Each of these two modules is translated to LLVM IR module, then they are +/// linked together and returned. +static std::unique_ptr +convertMLIRModule(Operation *op, llvm::LLVMContext &context) { + auto module = dyn_cast(op); + if (!module) + return op->emitError("op must be a 'builtin.module"), nullptr; + + std::unique_ptr kernelModule; + if (LinkNestedModules) { + // Verify that there is only one nested module. + auto modules = module.getOps(); + if (!llvm::hasSingleElement(modules)) { + module.emitError("The module must contain exactly one nested module"); + return nullptr; + } + + // Translate nested module and erase it. + ModuleOp nested = *modules.begin(); + kernelModule = translateModuleToLLVMIR(nested, context); + nested.erase(); + } + + std::unique_ptr mainModule = + translateModuleToLLVMIR(module, context); + + if (LinkNestedModules) + llvm::Linker::linkModules(*mainModule, std::move(kernelModule)); + + return mainModule; +} + int main(int argc, char **argv) { llvm::InitLLVM y(argc, argv); llvm::InitializeNativeTarget(); @@ -30,5 +88,7 @@ int main(int argc, char **argv) { mlir::DialectRegistry registry; mlir::registerAllToLLVMIRTranslations(registry); - return mlir::JitRunnerMain(argc, argv, registry); + mlir::JitRunnerConfig jitRunnerConfig; + jitRunnerConfig.llvmModuleBuilder = convertMLIRModule; + return mlir::JitRunnerMain(argc, argv, registry, jitRunnerConfig); } diff --git a/mlir/tools/mlir-spirv-cpu-runner/CMakeLists.txt b/mlir/tools/mlir-spirv-cpu-runner/CMakeLists.txt deleted file mode 100644 index 5760fad25ec65..0000000000000 --- a/mlir/tools/mlir-spirv-cpu-runner/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Linker -) - -if (MLIR_ENABLE_SPIRV_CPU_RUNNER) - message(STATUS "Building SPIR-V CPU runner") - - add_mlir_tool(mlir-spirv-cpu-runner - mlir-spirv-cpu-runner.cpp - ) - - llvm_update_compile_flags(mlir-spirv-cpu-runner) - - get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS) - - target_link_libraries(mlir-spirv-cpu-runner PRIVATE - ${conversion_libs} - MLIRAnalysis - MLIRArithDialect - MLIRBuiltinToLLVMIRTranslation - MLIRExecutionEngine - MLIRFuncDialect - MLIRGPUDialect - MLIRIR - MLIRJitRunner - MLIRLLVMDialect - MLIRLLVMToLLVMIRTranslation - MLIRMemRefDialect - MLIRParser - MLIRSPIRVDialect - MLIRTargetLLVMIRExport - MLIRTransforms - MLIRTranslateLib - MLIRSupport - ) -endif() diff --git a/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp b/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp deleted file mode 100644 index 22ad1024db4a0..0000000000000 --- a/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp +++ /dev/null @@ -1,90 +0,0 @@ -//===- mlir-spirv-cpu-runner.cpp - MLIR SPIR-V Execution on CPU -----------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Main entry point to a command line utility that executes an MLIR file on the -// CPU by translating MLIR GPU module and host part to LLVM IR before -// JIT-compiling and executing. -// -//===----------------------------------------------------------------------===// - -#include "mlir/Dialect/Arith/IR/Arith.h" -#include "mlir/Dialect/Func/IR/FuncOps.h" -#include "mlir/Dialect/GPU/IR/GPUDialect.h" -#include "mlir/Dialect/LLVMIR/LLVMDialect.h" -#include "mlir/Dialect/MemRef/IR/MemRef.h" -#include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h" -#include "mlir/ExecutionEngine/JitRunner.h" -#include "mlir/ExecutionEngine/OptUtils.h" -#include "mlir/Pass/Pass.h" -#include "mlir/Pass/PassManager.h" -#include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h" -#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" -#include "mlir/Target/LLVMIR/Export.h" - -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Linker/Linker.h" -#include "llvm/Support/InitLLVM.h" -#include "llvm/Support/TargetSelect.h" - -using namespace mlir; - -/// A utility function that builds llvm::Module from two nested MLIR modules. -/// -/// module @main { -/// module @kernel { -/// // Some ops -/// } -/// // Some other ops -/// } -/// -/// Each of these two modules is translated to LLVM IR module, then they are -/// linked together and returned. -static std::unique_ptr -convertMLIRModule(Operation *op, llvm::LLVMContext &context) { - auto module = dyn_cast(op); - if (!module) - return op->emitError("op must be a 'builtin.module"), nullptr; - // Verify that there is only one nested module. - auto modules = module.getOps(); - if (!llvm::hasSingleElement(modules)) { - module.emitError("The module must contain exactly one nested module"); - return nullptr; - } - - // Translate nested module and erase it. - ModuleOp nested = *modules.begin(); - std::unique_ptr kernelModule = - translateModuleToLLVMIR(nested, context); - nested.erase(); - - std::unique_ptr mainModule = - translateModuleToLLVMIR(module, context); - llvm::Linker::linkModules(*mainModule, std::move(kernelModule)); - return mainModule; -} - -int main(int argc, char **argv) { - llvm::InitLLVM y(argc, argv); - - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - mlir::JitRunnerConfig jitRunnerConfig; - jitRunnerConfig.llvmModuleBuilder = convertMLIRModule; - - mlir::DialectRegistry registry; - registry.insert(); - mlir::registerPassManagerCLOptions(); - mlir::registerBuiltinDialectTranslation(registry); - mlir::registerLLVMDialectTranslation(registry); - - return mlir::JitRunnerMain(argc, argv, registry, jitRunnerConfig); -}