Leaving the Sea of Nodes in the V8 JIT
v8.dev20 pointsby obl2 comments
int main(){
int x;
if (x <= 42){
assert(x != 12345);
}
}
is of course UB in C, even though under a "uninitialized is random" model the program is valid and does not assert (as the model checker concludes). In actual hardware shading is done 32 or 64 pixels at a time, not four. The problem above just got worse.
While it's true that there are "wasted" execution in 2x2 quads for derivative computation, it's absolutely not the case that all lanes of a hardware thread (warp / wavefront) have to come from the same triangle. That would be insanely inefficient. LOAD
DISPATCH
OP1
DISPATCH
OP2
... (once per operation in the expression)
STORE
... (once per row)
into DISPATCH
LOAD
OP1
STORE
LOAD
OP1
STORE
... (once per row)
DISPATCH
... (once per operation in the expression)
The nice trade-off here is that you don't require code generation to do that, but it's still not optimal. LOAD
OP1
OP2
...
STORE
LOAD
...
It helps because even though you can tune your batch size to get mostly cached loads and stores, it's still not free.
You can think of it as the rather classic "Vec of struct + numeric IDs" that is used a lot e.g. in Rust to represent complex graph-like structures.
This combined with bound checking is absolutely memory safe. It has a bunch of correctness issue that can arise due to index confusion but those are not safety issues. When combined with some kind of generational counters those correctness issue also go away but are only caught at runtime not at compile time (and they incur a runtime cost).
Rust's memory safety is about avoiding liveness issues (that become type confusions since all memory allocators will reuse memory for different types), nothing more, nothing less.