|
| 1 | +# Specialization constants. |
| 2 | + |
| 3 | +Specialization constant is basically a variable in a SYCL program set by host |
| 4 | +code and used in device code which appears to be constant for the online (JIT) |
| 5 | +compiler of the device code. Things like optimal tile size in a tiled matrix |
| 6 | +multiplication kernel may depend on the hardware and can be expressed via a |
| 7 | +specialization constant for better code generation. |
| 8 | + |
| 9 | +This version of oneAPI provides experimental implementation of specialization |
| 10 | +constants based on the |
| 11 | +[proposal](https://github.com/codeplaysoftware/standards-proposals/blob/master/spec-constant/index.md) |
| 12 | +from Codeplay. |
| 13 | + |
| 14 | +**NOTE:** _In future versions it may be superseded by [SYCL 2020 |
| 15 | +specification](https://www.khronos.org/registry/SYCL/specs/sycl-2020-provisional.pdf)._ |
| 16 | + |
| 17 | +A specialization constant is identified by a C++ type name, similarly to a |
| 18 | +kernel, its value is set via `program::set_spec_constant` class API and is |
| 19 | +"frozen" once the program is built. The following example shows how |
| 20 | +different values of a specialization constant can be used within the same |
| 21 | +kernel: |
| 22 | + |
| 23 | +```cpp |
| 24 | + for (int i = 0; i < n_sc_sets; i++) { |
| 25 | + cl::sycl::program program(q.get_context()); |
| 26 | + const int *sc_set = &sc_vals[i][0]; |
| 27 | + cl::sycl::ONEAPI::experimental::spec_constant<int32_t, SC0> sc0 = |
| 28 | + program.set_spec_constant<SC0>(sc_set[0]); |
| 29 | + cl::sycl::ONEAPI::experimental::spec_constant<int32_t, SC1> sc1 = |
| 30 | + program.set_spec_constant<SC1>(sc_set[1]); |
| 31 | + |
| 32 | + program.build_with_kernel_type<KernelAAA>(); |
| 33 | + |
| 34 | + try { |
| 35 | + cl::sycl::buffer<int, 1> buf(vec.data(), vec.size()); |
| 36 | + |
| 37 | + q.submit([&](cl::sycl::handler &cgh) { |
| 38 | + auto acc = buf.get_access<cl::sycl::access::mode::write>(cgh); |
| 39 | + cgh.single_task<KernelAAA>( |
| 40 | + program.get_kernel<KernelAAA>(), |
| 41 | + [=]() { |
| 42 | + acc[i] = sc0.get() + sc1.get(); |
| 43 | + }); |
| 44 | + }); |
| 45 | + } catch (cl::sycl::exception &e) { |
| 46 | + std::cout << "*** Exception caught: " << e.what() << "\n"; |
| 47 | + return 1; |
| 48 | + } |
| 49 | + ... |
| 50 | + } |
| 51 | +``` |
| 52 | +Here the values of specialization constants `SC0` and `SC1` are changed on |
| 53 | +every loop iteration. All what's needed is re-creating a `program` class |
| 54 | +instance, setting new values and rebuilding it via |
| 55 | +`program::build_with_kernel_type`. JIT compiler will effectively replace |
| 56 | +`sc0.get()` and `sc1.get()` within thhe device code with the corresponding |
| 57 | +constant values (`sc_vals[i][0]` and `sc_vals[i][1]`). Full runnable example |
| 58 | +can be found on |
| 59 | +[github](https://github.com/intel/llvm/blob/sycl/sycl/test/spec_const/spec_const_redefine.cpp). |
| 60 | +
|
| 61 | +Specialization constants can be used in programs compiled Ahead-Of-Time, in this |
| 62 | +case a specialization constant takes default value for its type (as specified by |
| 63 | +[C++ standard](https://en.cppreference.com/w/cpp/language/value_initialization)). |
| 64 | +
|
| 65 | +#### Limitations |
| 66 | +- The implementation does not support the `template <unsigned NID> struct spec_constant_id` |
| 67 | + API design for interoperability with OpenCL - to set specializataion constants |
| 68 | + in SYCL programs originating from external SPIRV modules and wrapped by OpenCL |
| 69 | + program objects. In SPIRV/OpenCL specialization constants are identified by an |
| 70 | + integer number, and the `spec_constant_id` class models that. |
| 71 | +- Only primitive numeric types are supported. |
| 72 | +
|
0 commit comments