obl
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.
The Elusive Frame Timing
2024 EuroLLVM – How Slow Is MLIR [video]
Maya as Editor: The game development approach of Santa Monica Studio [video]
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).(even in O1 clang gets rid of the whole function, including even the ret instruction, I'm surprised it does not at least leave an ud2 for an empty function to help debugging since it would not cost anything https://godbolt.org/z/eK8cz3EPe )
Parallel Query Systems: Demand-Driven Incremental Compilers [pdf]
2023 LLVM Dev Meetingg – Mojo: A system programming language [video]
eBPF: Unlocking the Kernel [Official Documentary] [video]
LLVM: Scalar Evolution (SCEV)
Unreal Engine 5: Nanite deep dive [pdf]
Chasing the Myth of Zero-Overhead Memory Safety
A CPU research kernel for cycle-by-cycle micro-architectural introspection
They seem to use 64 bit ones so this means that to overflow a single memory cell you would have to allocate and free it every cycle (!) at 4 ghz for about 150 years.
Basically as long as you accept this incredibly small "memory leak" you're fine.
From Stacks to Trees: A new aliasing model for Rust
V8 Maglev: compiler design doc
See e.g. https://fgiesen.wordpress.com/2011/07/05/a-trip-through-the-... for a nice detailed explanation.
For example, from the ISA docs [1], pixel waves are preloaded with an SGPR containing a bit mask indicating just that :
> The new_prim_mask is a 15-bit mask with one bit per quad; a one in this mask indicates that this quad begins a new primitive, a zero indicates it uses the same primitive as the previous quad. The mask is 15 bits, not 16, since the first quad in a wavefront begins a new primitive and so it is not included in the mask
The mask is used by the interp instructions to load the correct interpolants from local memory.
In fact, in the (older) GCN3 docs [2] there is a diagram showing the memory layout of attributes from multiple primitives for a single wavefront (page 99).
That being said, of course I expect this process to be "lazy" : you would not want to buffer execution of a partially filled thread forever, so depending on the workload you might measure different things.
[1] https://developer.amd.com/wp-content/resources/RDNA2_Shader_...
[2] http://developer.amd.com/wordpress/media/2013/12/AMD_GCN3_In...
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.I dont think that it's publicly documented how the "packing" of quads into lanes is done in the rasterizer for modern GPUs. I'd guess something opportunistic (maybe per tile) taking advantage of the general spatial coherency of triangles in mesh order.
Ownership You Can Count on [pdf]
A new runtime for Nim (2019)
Semantic Subtyping in Luau
SSA Translation is an Abstract Interpretation [pdf]
A Decade Verifying LLVM, or How to Retrofit Soundness in Industrial Software
Const Syntax in Rust
Carbon’s most exciting feature is its calling convention
However to me it seems that's completely orthogonal to the vector lanes : I don't see why two parallel lanes in a single thread (eg a 64-element GCN wavefront) would need cross-connected logic at the register file, since almost all instructions _do not_ read/write data from another lane.
There are a few cross-lane shuffles / reduce instruction but it seems to me that those would be handled in a dedicated execution unit. (they are not really the fast-path/common case)