# SPIR-V translation of WGSL pointers and references WGSL was updated to have two kinds of memory views: pointers and references. See https://github.com/gpuweb/gpuweb/pull/1569 In summary: * Reference types are never explicitly mentioned in WGSL source. * A use of a variable is a value of reference type corresponding to the reference memory view of the storage allocated for the variable. * Let-declared constants can be of pointer type, but not reference type. * Function parameter can be of pointer type, but not reference type. * A variable's store type is never a pointer type, and never a reference type. * The "Load Rule" allows a reference to decay to the underlying store type, by issuing a load of the value in the underlying memory. * For an assignment: * The right-hand side evaluates to a non-reference type (atomic-free plain type). * The left-hand side evaluates to a reference type, whose store type is the same as the result of evaluating the right hand side. * The address-of (unary `&`) operator converts a reference to a pointer. * The dereference (unary `*`) operator converts a pointer to a reference. TODO: Passing textures and samplers to helper functions might be done by "handler value", or by pointer-to-handle. ## Writing SPIR-V from WGSL The distinction in WGSL between reference and pointer disappears at the SPIR-V level. Both types map into pointer types in SPIR-V. To translate a valid WGSL program to SPIR-V: * The dereference operator (unary `*`) is the identity operation. * The address-of operator (unary `&`) is the identity operation. * Assignment maps to OpStore. * The Load Rule translates to OpLoad. ## Reading SPIR-V to create WGSL The main changes to the SPIR-V reader are: * When translating a SPIR-V pointer expression, track whether the corresponding WGSL expression is of corresponding WGSL pointer type or correspoinding WGSL type. * Insert dereference (unary-`*`) or address-of (unary-`&`) operators as needed to generate valid WGSL expressions. The choices can be made deterministic, as described below. The SPIR-V reader only supports baseline functionality in Vulkan. Therefore we assume no VariablePointers or VariablePointersStorageBuffer capabilities. All pointers are [SPIR-V logical pointers](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#LogicalPointerType). The [SPIR-V Universal Validation Rules](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_universal_validation_rules) specify where logical pointers can appear as results of instructions or operands of instructions. Each SPIR-V pointer result expression is a logical pointer, and therefore is one of: * OpVariable: map to the reference type. * OpFunctionParameter: map to the pointer type. * OpCopyObject: * When these only have one use, then these often fold away. Otherwise, they map to a a let-declared constant. * Map to the pointer type. * OpAccessChain, OpInBoundsAccessChain: * This could map to either pointer or reference, and adjustments in other areas could make it work. However, we recommend mapping this to the reference type. * OpImageTexelPointer is not supported in WGSL. It is used to get a pointer into a storage texture, for use with atomic instructions. But image atomics is not supported in WebGPU/WGSL. Each SPIR-V pointer operand is also a logical pointer, and is an operand to one of: * OpLoad Pointer operand: * Map to reference, inserting a dereference operator if needed. * OpStore Pointer operand: * Map to reference, inserting a dereference operator if needed. * OpStore Pointer operand: * OpAccessChain, OpInBoundsAccessChain Base operand: * WGSL array-access and subfield access only works on references. * [Gpuweb issue 1530](https://github.com/gpuweb/gpuweb/issues/1530) is filed to allow those operations to work on pointers. * Map to reference, inserting a dereference operator if needed. * OpFunctionCall function argument pointer operands * Function operands can't be references. * Map to pointer, inserting an address-of operator if needed. * OpAtomic instruction Pointer operand * These map to WGSL atomic builtins. * Map to pointer, inserting an address-of operator if needed. * Note: As of this writing, the atomic instructions are not supported by the SPIR-V reader. * OpCopyObject source operand * This could have been mapped either way, but it's easiest to map to pointer, to match the choice for OpCopyObject result type. * Map to pointer, inserting an address-of operator if needed. * OpCopyMemory, source and destination operands * This acts as an assignment. * Map both source and destination to reference, inserting dereference operators if needed. * Note: As of this writing, OpCopyMemory is not supported by the SPIR-V reader. * Extended instruction set instructions Modf and Frexp * These map to builtins. * Map the pointer operand to pointer, inserting an address-of operator if needed.