-
Notifications
You must be signed in to change notification settings - Fork 2
Updated spec constant proposal to use NTTP. #1
base: main
Are you sure you want to change the base?
Conversation
ff734d4
to
1873595
Compare
proposals/sycl_modules.md
Outdated
From the SYCL compiler's perspective (C++ compiler) the value is understood to be a runtime value and | ||
for this reason it is not possible to use such value in a `constexpr`. | ||
|
||
### Retrieving a spec constant placeholder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens for a program such as:
spec_id<int> id;
queue.submit([&](handler h) {
spec_constant<int, id> c1 = h.set_spec_constant<int, id>(1);
spec_constant<int, id> c2 = h.set_spec_constant<int, id>(2);
h.single_task([=]{
int v = c1.get_spec_constant();
});
});
Is this a valid program? What's the value of v
? Is it 1 if native_spec_constant()
is false and 2 if native_spec_constant()
is true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a valid program?
I think this should be banned, this look very odd and may induce unnecessary complexity on runtimes (whether there is native support or not). I'll clarify this.
Is it 1 if native_spec_constant() is false and 2 if native_spec_constant() is true?
In all cases the result of native_spec_constant()
does not affect the behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean with ban? UB or require compiler error? I think the first isn't reasonable and the 2nd isn't possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean with ban?
Runtime exception.
UB or require compiler error? I think the first isn't reasonable and the 2nd isn't possible.
i agree with you, I don't see why we would have an UB here and a compiler error is not always possible for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A runtime exception looks like a good approach to me too.
Note this behaviour is already stated on https://github.com/KhronosGroup/SYCL-Shared/pull/1/files#diff-dd15ce97b1565238f2c026fc84b30239R918 even with a more restrictive approach.
afc5b4f
to
5c6d8ed
Compare
This patch extended the module proposal to add better support for spec constant. It also introduce a different way to name spec constant values. Spec constant are named by creating an object of type `spec_id` and can be manipulated using NTTP.
…ec_constant per spec_id and per command group scope
5c6d8ed
to
72d7513
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great proposal!
A few nitpicks and some comments.
Please clarify the PR title.
proposals/sycl_modules.md
Outdated
template <typename T, typename ID = T> | ||
class spec_constant { | ||
template <typename T> | ||
class spec_id { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which is obviously 1.2.1 or 2020, right ?
The problem is that it is a niche concept, so it should not recycle some well known abbreviations...
What about just
class specialization_constant_id {
instead? Since it is just to declare some id, it should probably fit on 1 line anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reused the SPIR-V naming convention (OpSpecConstant
) as in-fine this is to allow its representation in SYCL.
I'm fine to change spec
to specialization
. I don't really see a need, but you are in a better position to say if this makes things easier to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the change in this commit, ad02463
I'm not convince we gain anything with this extra verbosity though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We gain a clarification between specification
and specialization
confusion.
Since this is a niche use case, I do not think it will jeopardize the programmer productivity but will help the reader not familiar with SPIR-V details...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will help the reader not familiar with SPIR-V details
Maybe I should stop following SPIR-V then :)
If you feel it is better, we'll stick to it, no strong opinion on this
proposals/sycl_modules.md
Outdated
From the SYCL compiler's perspective (C++ compiler) the value is understood to be a runtime value and | ||
for this reason it is not possible to use such value in a `constexpr`. | ||
|
||
### Retrieving a spec constant placeholder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A runtime exception looks like a good approach to me too.
Note this behaviour is already stated on https://github.com/KhronosGroup/SYCL-Shared/pull/1/files#diff-dd15ce97b1565238f2c026fc84b30239R918 even with a more restrictive approach.
proposals/sycl_modules.md
Outdated
- Getting the placeholder for a previously set specialization constant value; | ||
- If no specialization constant where ever set, then the *placeholder* object holds the default value of its `spec_id`. | ||
- Setting a specialization constant value and retrieving the placeholder | ||
- Performance notice: this function may cause the SYCL runtime to implicitly recompile the relevant SYCL module with the given value. This may have an important effect on performances and users should check their vendor recommendations on how to efficiently uses this functionality. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just think FPGA... ;-) But on the other hand an implementation could cache all the previous instances too... So it really depends on the use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can say you don't support the feature, or rely on a similar strategy as the host one.
I added this note it may not be obvious what is happening under the hood. I expect implementations to cache generated kernels, but if the user changes the value too often, there is nothing the runtime can really do and this will create a significant slowdown.
As this function is the most convenient one, I think it is important to mention it.
6d27d0c
to
b29123a
Compare
proposals/sycl_modules.md
Outdated
v 0.10: | ||
|
||
* Rework of the specialization constant proposal | ||
* Add `specialization _id` and `specialization _constant` definitions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious spaces before _
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's odd,
anyway, now fixed
// Available if module_status::executable | ||
// Retrieve the value of the specialization constant associated with this module. | ||
// Call only valid from the host. | ||
template<class T, specialization_id<T>& s> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After a second review I have just realized the &
here, meaning that the id is actually the address of the specialization_id
object...
This changes quite a lot in my understanding of the design...
|
||
// Available if module_status::executable | ||
// Only from C++17 | ||
// Set the value of the specialization constant. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Set the value of the specialization constant. | |
// Get the value of the specialization constant. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
proposals/sycl_modules.md
Outdated
// Call only valid from the host. | ||
template<auto& s> | ||
specialization_constant<typename std::remove_reference_t<decltype(s)>::type, s> | ||
get_specialization_constant(handler&); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While waiting for concepts to be mandatory in SYCL, at least you should specificy in the comment that s
needs to be an existing specialization identier or it will throw. Also that the specialization constant has been previously initialized.
proposals/sycl_modules.md
Outdated
|
||
// Available if module_status::executable | ||
// Retrieve the value of the specialization constant associated with this module. | ||
// Call only valid from the host. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also that the specialization constant has been previously initialized or it will throw.
proposals/sycl_modules.md
Outdated
`specialization_id` is used by the *SYCL implementation* to *reference* constant whose | ||
concrete value will only be known during the application execution. | ||
To create a new `specialization_id` in a module, the user creates a `specialization_id` object with an *automatic* or *static* storage duration in the namespace or class scope. | ||
The user then uses references to this object to bind the `specialization_constant` value to the *identifier*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think it binds the specialization_constant
value to the identifier.
If I understand correctly it binds the specialization_constant
value to the identifier and the command-group handler.
So a single specialization_id` object can be used to define different constant in different kernels.
To create a new `specialization_id` in a module, the user creates a `specialization_id` object with an *automatic* or *static* storage duration in the namespace or class scope. | ||
The user then uses references to this object to bind the `specialization_constant` value to the *identifier*. | ||
|
||
`specialization_id` objects must be forward declarable and cannot be moved or copied. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I understand that you are interested in the address of the object and not the value of the object, I need to think about how it works with extern
and multiple translation units.
The object could be moved or copied but at the end it is just another object with a different address, so it represents another specialization_id
.
Also since you are interested by the address, why do you care about "objects must be forward declarable"?
This address mechanism is different from the type approach used to name kernels and global pipes in Intel extension. Is it really simpler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After playing with this, it looks like the specialization_id
objects needs static storage.
But by looking at the C++20 draft, I cannot see this restriction in 13.4.2 Template non-type arguments [temp.arg.nontype]
Some experiment in https://github.com/keryell/teaching_C-plus-plus/blob/master/NTTP_ref.cpp and https://github.com/keryell/teaching_C-plus-plus/blob/master/NTTP_ref_2.cpp
// This allow the user to setup a default value for the specialization_id instance. | ||
// The initialization of T must be evaluated at compile time to be valid. | ||
template<class... Args > | ||
explicit constexpr specialization_id(Args&&...); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this take a parameter pack rather than an argument of type T?
@hfinkel gave a presentation in Prague during ISO C++ SG7: P1609R3 "C++ Should Support Just-in-Time Compilation" http://wg21.link/p1609 which reminded me this discussion. cplusplus/papers#388 At least his paper adds a new C++ paradigm that might be similar to this concept of specialization constant, from a C++ perspective. It could give to specialization constant a kind of true C++ citizenship... |
This new proposal remove the need to use `spec_constant` object and uses a kernel handler instead to retrieve the values. Signed-off-by: Victor Lomuller <[email protected]>
Whilst writing the wording for the proposal I have made some observations/alterations:
|
This patch extended the module proposal to add better support for spec constant.
It also introduce a different way to name spec constant values.
Spec constant are named by creating an object of type
spec_id
and can be manipulated using NTTP.