spirv2clc is an experimental OpenCL SPIR-V to OpenCL C translator currently
targeting OpenCL 1.2 support. It can generate OpenCL C code equivalent to an
input OpenCL SPIR-V module. The generated code is not meant to be human-readable
and closely follows the input SPIR-V. It is intended to be used as a means for
OpenCL applications that require SPIR-V to run on OpenCL implementations that
only support OpenCL C.
This project depends on the following other projects:
spirv2clc uses CMake as its build system and the following should work on most systems:
git submodule update --init mkdir build cd build cmake .. cmake --build .
Using the translator tool
A command line translator tool is provided and can be used as follows:
The translated source is printed to the standard output.
The tool supports the following options:
--asmtreat the input as SPIR-V assembly in text form.
Embedding as a library
spirv2clc can be embedded as a library and used as follows:
#include "spirv2clc.h" spirv2clc::translator translator; std::string srcgen; std::vector<uint32_t> binary; int err = translator.translate(binary, &srcgen);
Running with test layer
A layer that enables a round-trip translation of OpenCL C programs to SPIR-V and
back to OpenCL C is provided for testing purposes. It intercepts OpenCL calls
performed by applications and calls offline tools to handle program substitutions.
The flow is as follows:
- Intercept program creation OpenCL calls
- Save sources
- Compile to LLVM IR (using
- Translate LLVM IR to SPIR-V (using
- Translate back to OpenCL C (using
The layer expects the following tools to be in the
and can be used as follows:
LD_PRELOAD=./build/testlayer/libtestlayer.so \ PATH=/path/to/build:/path/to/other-tools:$PATH \ /path/to/opencl-application
spirv2clc uses SPIRV-Tools’s IR and type analysis utilities and provides a
single-pass (with some additional searching) translation of the input module.
The code generation process is rather straightforward and the generated code
closely follows the input SPIR-V with a few notable exceptions:
OpPhi‘s are analysed at the beginning of each function’s translation to
record a full list of all of
OpPhi‘s used by the function as well as all the
variables and parents they can take as input. A variable is declared for each
OpPhiat the beginning of each translated function and assigned at the end of
each basic block that can be a parent to the
Kernel scope variables in the local address space are global variables in
SPIR-V modules. At the beginning of each kernel function’s translation, its
static call tree is inspected to build a list of all the variables in the
local address space it’s using. A declaration is generated at the beginning of
the kernel function’s source for each variable.
Pointer to arrays are generated as pointers to array elements.
Built-in variables are handled in the translationg of their uses.
Booleans are translated to an appropriate (vector) integer type according to
the rules for their producer (see §6.5.4 as an example for relational operators).
All control flow is translated to
- No support for images
- No support for relaxed atomics
- Nesting of arrays and structures probably needs more work
- OpCompositeExtract doesn’t support multiple indices