Skip to content

Commit 71ece59

Browse files
committed
Apply comments, update integration footer section
1 parent 86853e2 commit 71ece59

File tree

1 file changed

+143
-34
lines changed

1 file changed

+143
-34
lines changed

sycl/doc/SYCL2020-SpecializationConstants.md

Lines changed: 143 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -678,12 +678,19 @@ property_set {
678678
### DPC++ Compiler: front-end
679679

680680
DPC++ FE is responsible for several things related to specialization constants:
681-
1. Handling of `kernel_handler` SYCL kernel function argument.
682-
2. Communicating to DPC++ RT which kernel argument should be used for passing
683-
buffer with specialization constants values when they are emulated.
684-
3. Communicating to DPC++ RT mapping between `specialization_id`s and
685-
corresponding symbolic IDs through integration footer.
686-
4. It provides `__builtin_unique_ID` implementation.
681+
682+
While transforming SYCL kernel function into an OpenCL kernel, DPC++ FE should
683+
- Handle `kernel_handler` argument: it is not captured by lambda and therefore
684+
should be separately handled in DPC++ FE
685+
- Communicate to DPC++ RT which kernel argument should be used for passing
686+
a buffer with specialization constant values when they are emulated.
687+
688+
DPC++ FE provides implementation of `__builtin_unique_ID` built-in function and
689+
it also populates special integration footer with the content required by DPC++
690+
RT for access to right device image properties describing specialization
691+
constants.
692+
693+
#### SYCL Kernel function transformations
687694

688695
`kernel_handler` is defined by SYCL 2020 specification as interface for
689696
retrieving specialization constant values in SYCL kernel functions, but it
@@ -743,21 +750,46 @@ integration header mechanism, i.e. it is added as new entry to
743750
`kernel_signatures` structure there with parameter kind set to a new
744751
enumeration value `kernel_param_kind_t::kind_specialization_constants_buffer`.
745752

746-
Those were descriptions of tasks (1) and (2) of DPC++ FE. Task (3) is to help
747-
DPC++ RT to connect user-provided `specialization_id` variable with
748-
corresponding symbolic ID of a specialization constant when
749-
`handler::set_specialization_constant` is invoked.
753+
#### `__builtin_unique_ID`
750754

751-
As noted above, we can't use regular integration header here, because in general
752-
case, `specialization_id` variables can't be forward-declared. Therefore, we are
753-
using integration footer approach, which for the following code snippet:
755+
This built-in is used to generate unique identifiers for specialization
756+
constants, which are used in communication between the compiler and the runtime.
757+
758+
`__builtin_unique_ID` is defined as follows: it accepts a variable and returns
759+
a C-string (`const char *`), which:
760+
- if the input variable has external linkage, the string must be the same in all
761+
translation units that pass this same variable to the built-in.
762+
- if the input variable has internal linkage, the string must be unique across
763+
all translation units.
764+
- return string must be the same if the built-in was called twice for the same
765+
variable within a single translation unit (regardless of its linkage type).
766+
767+
#### Integration footer generation
768+
769+
Note: we could have used `__builtin_unique_ID` directly in DPC++ Headers, but
770+
this would break compilation of those with a third-party C++ 17-compatible
771+
compiler, which is unaware of this built-in function. Therefore, the compiler
772+
generates a header file, which includes _the result_ of calling
773+
`__builtin_unique_ID` function and it is included into the user's program. By
774+
doing so we can still use this non-standard built-in function and preserve
775+
support for third-party host compilers.
776+
777+
However, as noted above, we can't use regular integration header here, because
778+
in general case, `specialization_id` variables can't be forward-declared.
779+
Therefore, we are using _integration footer_ approach, i.e. we generate a header
780+
file which must be included at the end of a translation unit.
781+
782+
For the following code snippet:
754783
```
755784
struct A {
756785
float a, b;
757786
};
758787
759788
constexpr specialization_id<int> id_int;
760-
constexpr specialization_id<A> id_A;
789+
struct Wraper {
790+
public:
791+
static constexpr specialization_id<A> id_A;
792+
};
761793
constexpr inline specialization_id<double> id_double;
762794
constexpr inline specialization_id<float> id_float;
763795
// ...
@@ -767,20 +799,19 @@ constexpr inline specialization_id<float> id_float;
767799
// ...
768800
[=](kernel_handler h) {
769801
h.get_specialization_constant<id_int>();
770-
h.get_specialization_constant<id_A>();
802+
h.get_specialization_constant<Wrapper::id_A>();
771803
}
772804
}
773805
```
774806

775-
Will look like:
807+
The integration footer will look like:
776808

777809
```
778810
namespace detail {
779-
// generic declaration
780-
template<auto &SpecName>
781-
inline const char *get_spec_constant_symbolic_ID();
811+
// Note: we do not declare `get_spec_constant_symbolic_ID` here and assume that
812+
// it is declared in some other header which was already included.
782813
783-
// specializations for each specialization constant:
814+
// specializations for each specialization constant (for each `specialization_id`):
784815
// we can refer to all those specialization_id variables, because integration
785816
// footer was _appended_ to the user-provided translation unit
786817
template<>
@@ -789,8 +820,8 @@ inline const char *get_spec_constant_symbolic_ID<id_int>() {
789820
}
790821
791822
template<>
792-
inline const char *get_spec_constant_symbolic_ID<id_A>() {
793-
return "result of __builtin_unique_ID(id_A) encoded here";
823+
inline const char *get_spec_constant_symbolic_ID<Wrapper::id_A>() {
824+
return "result of __builtin_unique_ID(Wrapper::id_A) encoded here";
794825
}
795826
796827
template<>
@@ -814,19 +845,97 @@ definition of `specialization_id` object regardless of its uses within SYCL
814845
kernel functions: those IDs are used by DPC++ RT as well even for those spec
815846
constants, which are never accessed on device.
816847

817-
NOTE: By direct using `__builtin_unique_ID` in DPC++ Headers we could avoid
818-
generating integration footer at all, but since the host part of the program can
819-
be compiled with a third-party C++ 17-compatible compiler, which is unaware of
820-
the clang-specific built-ins, it can result in build errors.
821848

822-
`__builtin_unique_ID` is defined as follows: it accepts a variable and returns
823-
a C-string (`const char *`), which:
824-
- if the variable has external linkage, the string must be consistent in all
825-
translation units that reference this same variable.
826-
- if the variable has internal linkage, the string must be unique across all
827-
translation units.
828-
- return string must be the same if the built-in was called twice for the same
829-
variable within a single translation unit.
849+
##### Ambiguous references to specialization_id
850+
851+
There are valid C++ code examples, where references to `specialization_id`
852+
variables could be ambiguous if they just referenced from a global namespace
853+
like shown above. For example:
854+
855+
```
856+
constexpr sycl::specialization_id<int> same_name{1};
857+
858+
/* application code that references "::same_name" */
859+
860+
namespace {
861+
constexpr sycl::specialization_id<int> same_name{2}:
862+
/* application code that referenes ::(unnamed)::same_name */
863+
namespace {
864+
constexpr sycl::specialization_id<int> same_name{3}:
865+
/* application code that referenes ::(unnamed)::(unnamed)::same_name */
866+
}
867+
}
868+
869+
/* application code that references "::same_name" */
870+
```
871+
872+
In that case we can't use `same_name` for specializing
873+
`get_spec_constant_symbolic_ID`, because it would be ambiguous reference.
874+
However, we can do the following trick:
875+
876+
```
877+
// Content of integration footer for the example above
878+
879+
// For unambiguous references we can generate regular specialization
880+
template<>
881+
inline const char *get_spec_constant_symbolic_ID<::same_name>() {
882+
return "result of __builtin_unique_ID(::same_name) encoded here";
883+
}
884+
885+
// For ambiguous references we generate 'shim' functions, which allows us to
886+
// get an address of a variable within a (possible nested) anonymous namespace
887+
// without spelling it.
888+
namespace {
889+
namespace __sycl_detail {
890+
// This helper is need to get addresses of variables defined within
891+
// anonymous namespace.
892+
// It is generated for each specialization_id within an anonymous namespace
893+
// if there is the same specialization_id defined in global namespace
894+
static constexpr decltype(spec_name) __spec_id_shim_0() {
895+
// address of ::(unnamed)::same_name;
896+
return spec_name;
897+
}
898+
}
899+
}
900+
namespace sycl {
901+
namespace detail {
902+
// By using 'shim' function were are able to unambiguously refer to a
903+
// variable within an anonymous namespace
904+
template<>
905+
inline const char *get_spec_constant_symbolic_ID<::__sycl_detail::__spec_id_shim_0()>() {
906+
return "unique id for ::(unnamed)::same_name";
907+
}
908+
}
909+
}
910+
namespace {
911+
namespace {
912+
namespace __sycl_detail {
913+
static constexpr decltype(same_name) &spec_id_shim_1() {
914+
// address of ::(unnamed)::(unnamed)::same_name;
915+
return same_name;
916+
}
917+
}
918+
}
919+
920+
namespace __sycl_detail {
921+
// Sometimes we need a 'shim', which points to another 'shim' in order to
922+
// "extract" a variable from an anonymous namespace unambiguosly
923+
static constexpr decltype(__sycl_detail::__spec_id_shim_1()) &__spec_id_shim_2() {
924+
// still address of ::(unnamed)::(unnamed)::same_name;
925+
return __sycl_detail::__spec_id_shim_1();
926+
}
927+
}
928+
}
929+
namespace sycl {
930+
namespace detail {
931+
template<>
932+
inline const char *get_spec_constant_symbolic_ID<::__sycl_detail::__spec_id_shim_2()>() {
933+
return "unique id for ::(unnamed)::(unnamed)::same_name";
934+
}
935+
}
936+
}
937+
938+
```
830939

831940
### DPC++ runtime
832941

0 commit comments

Comments
 (0)