If WGSL supports atomic operations, it should support volatile atomic operations.
Since we haven't discussed atomic operations yet, it's too early to suggest syntax. We might want to use a 'volatile' keyword or attribute, or embed it in a built-in function name.
Justification:
In C++ much of the 'volatile' functionality has rightly moved into atomics. See P1152R0 Deprecating volatile
However it still has a reason to exist when used with atomics, and that use carries over into the GPU world.
Consider the following C++ program as the action of a single thread:
#include <atomic>
std::atomic<int> flag;
int main() {
int sub_counter = 0;
flag.store(0, std::memory_order_relaxed);
// Wait for another thread to modify 'flag'.
while(flag.load(std::memory_order_relaxed) == 0) {
sub_counter++;
}
return sub_counter & 1;
}
The implementation is justified in the following transformation:
- First, constrain and therefore assume a restricted set of schedules of the operations in this thread and the other signaling thread (that we don't see)
- Therefore, assume that the atomic loads in this thread are scheduled "before" the writes in the other thread. Without progress fairness guarantees, this is justified
- Therefore, all the atomic loads can be combined, and then moved before the loop.
So we could end up compiling into the equivalent of the following:
#include <atomic>
std::atomic<int> flag;
int main() {
int sub_counter = 0;
flag.store(0, std::memory_order_relaxed);
const int loaded = flag.load(std::memory_order_relaxed);
while(loaded == 0) {
sub_counter++;
}
return sub_counter & 1;
}
This is probably not what the programmer wanted.
To the fix this, the programmer should use 'volatile' to indicate that the atomic loads on 'flag' are not to be combined with other memory operations.
Currently this is denoted in C++ by marking 'flag' itself with 'volatile'. If there were no legacy here we'd make the operation volatile, not the object itself. In SPIR-V with the Vulkan memory model, use the Volatile memory semantics bit (on atomic operations and fences/memory barriers), Volatile memory operand (on Load and Store), and VolatileTexel (on image operations).
More background:
(Actually, the signed integer overflow on sub_counter in the example is undefined behaviour and the compiler could delete the entire program or your hard drive. Changing sub_counter to unsigned fixes that issue, I think.)
If WGSL supports atomic operations, it should support volatile atomic operations.
Since we haven't discussed atomic operations yet, it's too early to suggest syntax. We might want to use a 'volatile' keyword or attribute, or embed it in a built-in function name.
Justification:
In C++ much of the 'volatile' functionality has rightly moved into atomics. See P1152R0 Deprecating volatile
However it still has a reason to exist when used with atomics, and that use carries over into the GPU world.
Consider the following C++ program as the action of a single thread:
The implementation is justified in the following transformation:
So we could end up compiling into the equivalent of the following:
This is probably not what the programmer wanted.
To the fix this, the programmer should use 'volatile' to indicate that the atomic loads on 'flag' are not to be combined with other memory operations.
Currently this is denoted in C++ by marking 'flag' itself with 'volatile'. If there were no legacy here we'd make the operation volatile, not the object itself. In SPIR-V with the Vulkan memory model, use the Volatile memory semantics bit (on atomic operations and fences/memory barriers), Volatile memory operand (on Load and Store), and VolatileTexel (on image operations).
More background:
(Actually, the signed integer overflow on
sub_counterin the example is undefined behaviour and the compiler could delete the entire program or your hard drive. Changingsub_counterto unsigned fixes that issue, I think.)