No Aliasing
To achieve maximum throughput, GPU compilers must aggressively optimize memory accesses. They load values into physical registers, reorder read and write instructions to hide latency, and combine consecutive operations. However, if two different variables in a function can refer to the exact same physical memory cell—a condition known as aliasing—these optimizations become incredibly hazardous.
To guarantee safety and allow peak performance without complex runtime checks, WGSL enforces a strict Static Alias Analysis rule at compile time.
Why WGSL Bans Pointer Aliasing
In traditional systems languages like C, if two pointers p1 and p2 point to the same variable, writing to *p1 silently changes the value read from *p2. Because the compiler cannot always prove whether two pointers alias, it must defensively reload values from slow RAM or cache instead of keeping them in ultra-fast registers.
On massive GPU architectures, this defensive reloading would severely bottleneck execution. WGSL's no-aliasing rule guarantees to the compiler that no two active access paths within a function call stack can point to overlapping memory if any of them is used to write. This enables:
- Aggressive Register Promotion: The compiler can confidently keep variables in GPU core registers for the entire duration of a function call.
- Instruction Pipelining & Reordering: The hardware can execute reads and writes in parallel or out of order to saturate the memory bus.
- Deterministic Execution: Prevents silent, vendor-dependent memory corruption or race conditions within a single thread.
Visualizing Aliasing Access Paths
Below is a comparison of how WGSL's static analysis evaluates pointer access paths.
OVERLAPPING ACCESS PATHS
COMPILER ERRORTwo pointers (or a pointer and a module-scope variable) both target the same root memory location, and at least one path is used for writing.
DISJOINT ACCESS PATHS
VALID COMPILEPointers target completely separate, independent memory allocations. No overlap is possible, ensuring hazard-free optimization.
The Static No-Aliasing Rule
WGSL's static analysis checker determines whether a program is valid using a precise checklist. Specifically, shader creation fails if:
- A pointer is passed as an argument to a user-declared function.
- The called function (or any function in the call stack it triggers) has two distinct views (pointers or references) into the same original root variable.
- At least one of those views is used for a potential write.
Control Flow Ignored Completely
The compiler's check for a "potential write" is a static syntactic analysis. It completely ignores control flow.
If a function contains a branch like if (false) { *p = 5; }, the write is physically impossible at runtime. However, the static analysis still classifies this as a potential write. Consequently, passing the same root variable as an alias to this function will trigger a compile-time error. This keeps the compiler extremely fast and completely deterministic.
The interactive code editor demonstrates valid and invalid cases where a helper function writes via a pointer parameter p, but reads from a module-scope private variable x. Passing the address of x (i.e. &x) as the argument p would result in two overlapping views, creating an illegal alias!
/*
* Copyright ©2026 Michael R. Bernstein. All new modifications licensed under Apache 2.0.
* Upstream lineage ©2023 governed by original BSD 3-Clause. See README.md.
*/
var<private> x: i32;
var<private> y: i32;
fn set_from_x(p : ptr<private, i32>) {
*p = x; // Writes via p, reads via module-scoped x.
}
// Alias analysis ignores control flow, so the analysis thinks this
// function writes via p, and reads via module-scoped x.
fn dont_set_from_x(p : ptr<private, i32>) {
if (false) {
*p = x; // Still counts as a potential write.
}
}
fn main() {
// set_from_x(&x); // Error: set_from_x would have two views of x.
// There would be a write x through *p
// dont_set_from_x(&x); // Still an error.
// But this is fine, since x and y don't alias.
set_from_x(&y);
}