[Mlir-commits] [mlir] be96137 - [MLIR][SPIRVToLLVM] Updated documentation on spirv-cpu-runner
George Mitenkov
llvmlistbot at llvm.org
Mon Dec 21 14:50:30 PST 2020
Author: George Mitenkov
Date: 2020-12-22T01:47:43+03:00
New Revision: be961374611a4be1b042cce7e6cc4cd12a1b4fd7
URL: https://github.com/llvm/llvm-project/commit/be961374611a4be1b042cce7e6cc4cd12a1b4fd7
DIFF: https://github.com/llvm/llvm-project/commit/be961374611a4be1b042cce7e6cc4cd12a1b4fd7.diff
LOG: [MLIR][SPIRVToLLVM] Updated documentation on spirv-cpu-runner
This patch adds documentation for the `mlir-spirv-cpu-runner`.
It provides an overview of applied transformations and passes, as
well as an example walk-through.
Some typos in the documentation have been fixed as well.
Reviewed By: mravishankar
Differential Revision: https://reviews.llvm.org/D93620
Added:
Modified:
mlir/docs/SPIRVToLLVMDialectConversion.md
Removed:
################################################################################
diff --git a/mlir/docs/SPIRVToLLVMDialectConversion.md b/mlir/docs/SPIRVToLLVMDialectConversion.md
index 3aa4d0fa43a19..bdae08c1e230f 100644
--- a/mlir/docs/SPIRVToLLVMDialectConversion.md
+++ b/mlir/docs/SPIRVToLLVMDialectConversion.md
@@ -377,7 +377,7 @@ entry points in LLVM. At the moment, we use the following approach:
entry point. For example, `LocalSize` provides information about the
work-group size that can be reused.
- In order to preserve this inforamtion, `spv.ExecutionMode` is converted to
+ In order to preserve this information, `spv.ExecutionMode` is converted to
a struct global variable that stores the execution mode id and any variables
associated with it. In C, the struct has the structure shown below.
@@ -816,7 +816,140 @@ to LLVM ops. At the moment, SPIR-V module attributes are ignored.
## `mlir-spirv-cpu-runner`
-**Note: this is a section in progress, more information will appear soon**
+`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.
+
+To build the runner, add the following option to `cmake`:
+```bash
+-DMLIR_SPIRV_CPU_RUNNER_ENABLED=1
+```
+
+### Pipeline
+
+The `gpu` module with the kernel and the host code undergo the following
+transformations:
+
+* Convert the `gpu` module into SPIR-V dialect, lower ABI attributes and
+ update version, capability and extension.
+
+* Emulate the kernel call by converting the launching operation into a normal
+ function call. The data from the host side to the device is passed via
+ copying to global variables. These are created in both the host and the
+ kernel code and later linked when nested modules are folded.
+
+* Convert SPIR-V dialect kernel to LLVM dialect via the new conversion path.
+
+After these passes, the IR transforms into a nested LLVM module - a main module
+representing the host code and a kernel module. These modules are linked and
+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
+simplicity some type annotations and function implementations have been
+omitted).
+
+```mlir
+gpu.module @foo {
+ gpu.func @bar(%arg: memref<8xi32>) {
+ // Kernel code.
+ gpu.return
+ }
+}
+
+func @main() {
+ // Fill the buffer with some data
+ %buffer = alloc : memref<8xi32>
+ %data = ...
+ call fillBuffer(%buffer, %data)
+
+ "gpu.launch_func"(/*grid dimensions*/, %buffer) {
+ kernel = @foo::bar
+ }
+}
+```
+
+Lowering `gpu` dialect to SPIR-V dialect results in
+
+```mlir
+spv.module @__spv__foo /*VCE triple and other metadata here*/ {
+ spv.globalVariable @__spv__foo_arg bind(0,0) : ...
+ spv.func @bar() {
+ // Kernel code.
+ }
+ spv.EntryPoint @bar, ...
+}
+
+func @main() {
+ // Fill the buffer with some data.
+ %buffer = alloc : memref<8xi32>
+ %data = ...
+ call fillBuffer(%buffer, %data)
+
+ "gpu.launch_func"(/*grid dimensions*/, %buffer) {
+ kernel = @foo::bar
+ }
+}
+```
+
+Then, the lowering from standard dialect to LLVM dialect is applied to the host
+code.
+
+```mlir
+spv.module @__spv__foo /*VCE triple and other metadata here*/ {
+ spv.globalVariable @__spv__foo_arg bind(0,0) : ...
+ spv.func @bar() {
+ // Kernel code.
+ }
+ spv.EntryPoint @bar, ...
+}
+
+// Kernel function declaration.
+llvm.func @__spv__foo_bar() : ...
+
+llvm.func @main() {
+ // Fill the buffer with some data.
+ llvm.call fillBuffer(%buffer, %data)
+
+ // Copy data to the global variable, call kernel, and copy the data back.
+ %addr = llvm.mlir.addressof @__spv__foo_arg_descriptor_set0_binding0 : ...
+ "llvm.intr.memcpy"(%addr, %buffer) : ...
+ llvm.call @__spv__foo_bar()
+ "llvm.intr.memcpy"(%buffer, %addr) : ...
+
+ llvm.return
+}
+```
+
+Finally, SPIR-V module is converted to LLVM and the symbol names are resolved
+for the linkage.
+
+```mlir
+module @__spv__foo {
+ llvm.mlir.global @__spv__foo_arg_descriptor_set0_binding0 : ...
+ llvm.func @__spv__foo_bar() {
+ // Kernel code.
+ }
+}
+
+// Kernel function declaration.
+llvm.func @__spv__foo_bar() : ...
+
+llvm.func @main() {
+ // Fill the buffer with some data.
+ llvm.call fillBuffer(%buffer, %data)
+
+ // Copy data to the global variable, call kernel, and copy the data back.
+ %addr = llvm.mlir.addressof @__spv__foo_arg_descriptor_set0_binding0 : ...
+ "llvm.intr.memcpy"(%addr, %buffer) : ...
+ llvm.call @__spv__foo_bar()
+ "llvm.intr.memcpy"(%buffer, %addr) : ...
+
+ llvm.return
+}
+```
[LLVMFunctionAttributes]: https://llvm.org/docs/LangRef.html#function-attributes
[SPIRVFunctionAttributes]: https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_function_control_a_function_control
More information about the Mlir-commits
mailing list