Name Strings

SPV_KHR_untyped_pointers

Contact

To report problems with this extension, please open a new issue at:

Contributors

  • Alan Baker, Google

  • David Neto, Google

  • Hugo Devillers, Saarland University

  • Tobias Hector, AMD

  • Caio Oliveira, Intel

  • Graeme Leese, Broadcom

  • Ruihao Zhang, Qualcomm,

  • Dmitry Sidorov, Intel

  • Jeff Bolz, Nvidia

  • Victor Lomuller, Codeplay

  • Kevin Petit, Arm

  • Ben Ashbaugh, Intel

  • Viktoria Maksimova, Intel

Notice

Copyright (c) 2024 The Khronos Group Inc. Copyright terms at http://www.khronos.org/registry/speccopyright.html

Status

Provisional

  • Approved by the SPIR-V Working Group: 2024-05-29

  • Approved by the Khronos Board of Promoters: 2024-07-12

Final

  • Approved by the SPIR-V Working Group: 2025-05-13

  • Approved by the Khronos Board of Promoters: 2025-06-27

Version

Last Modified Date

2025-01-16

Revision

3

Dependencies

This extension is written against the SPIR-V Specification, Version 1.6 Revision 5.

This extension modifies the following extensions:

This extension modifies the OpenCL.std extended instruction set.

Overview

This extension introduces support for untyped pointers. It allows for the declaration and use of pointers that do not specify the type of data they point to. It also allows memory, atomic and other instructions to reinterpret data differently than the declared type of the variables they are used with. For example, loading a vector of floating-point values from a variable with a declared type of an array of integers. It provides an equivalent set of functionality to type-punning via pointer casting in high-level languages.

This extension adds the following new instructions:

Extension Name

To use this extension within a SPIR-V module, the following OpExtension must be present in the module:

OpExtension "SPV_KHR_untyped_pointers"

Modifications to the SPIR-V Specification, Version 1.6

Modify Section 2.2.1 Instructions:

Add the following new term:

Variable: An OpVariable or OpUntypedVariableKHR.

Change the following existing terms:

Object: An instantiation of a non-void type, either as the Result <id> of an operation, or created through a variable.

Memory Object: An object created through a variable. Such an object exists only for the duration of a function if it is a function variable, and otherwise exists for the duration of the invocation.

Memory Object Declaration: A variable, or an OpFunctionParameter of pointer type, or the contents of a variable that holds either a pointer to the PhysicalStorageBuffer storage class or an array of such pointers.

Intermediate Object or Intermediate Value or Intermediate Result: An object created by an operation (not memory allocated by a variable) and dying on its last consumption.

Modify Section 2.2.2 Types:

Add the following new term:

Pointer Type: An OpTypePointer or OpTypeUntypedPointerKHR.

Changes the following existing terms:

Physical Pointer Type: A pointer type whose Storage Class uses physical addressing according to the addressing model.

Variable Pointer: A pointer of logical pointer type that results from one of the following opcodes:

Additionally, any OpAccessChain, OpInBoundsAccessChain, OpUntypedAccessChainKHR, OpUntypedInBoundsAccessChainKHR or OpCopyObject that takes a variable pointer as an operand also produces a variable pointer. An OpFunctionParameter of pointer type is a variable pointer if any OpFunctionCall to the function statically passes a variable pointer as the value of the parameter.

Modify Section 2.4 Logical Layout of a Module:

Change references to OpVariable to variable.

Modify Section 2.16.1 Universal Validation Rules:

Modify the list items under the following list item:

If neither the VariablePointers nor VariablePointersStorageBuffer capabilities are declared, the following rules apply to logical pointer types:

Change:

OpVariable must not allocate an object whose type is or contains a logical pointer type.

To:

Variables must not allocate an object whose type is or contains a logical pointer type.

Change:

It is invalid for a pointer to be an operand to any instruction other than:

  • OpLoad

  • OpStore

  • OpAccessChain

  • OpInBoundsAccessChain

  • OpFunctionCall

  • OpImageTexelPointer

  • OpCopyMemory

  • OpCopyObject

  • OpArrayLength

  • all OpAtomic instructions

  • extended instruction-set instructions that are explicitly identified as taking pointer operands

To:

It is invalid for a pointer to be an operand to any instruction other than:

Change:

It is invalid for a pointer to be the Result <id> of any instruction other than:

  • OpVariable

  • OpAccessChain

  • OpInBoundsAccessChain

  • OpFunctionParameter

  • OpImageTexelPointer

  • OpCopyObject

To:

It is invalid for a pointer to be the Result <id> of any instruction other than:

Change:

All indexes in OpAccessChain and OpInBoundsAccessChain that are OpConstant with type of OpTypeInt with a signedness of 1 must not have their sign bit set.

To:

All indexes in OpAccessChain, OpInBoundsAccessChain, OpUntypedAccessChainKHR and OpUntypedInBoundsAccessChainKHR that are OpConstant with type of OpTypeInt with a signedness of 1 must not have their sign bit set.

Modify the list items under the following list item:

If the VariablePointers or VariablePointersStorageBuffer capability is declared, the following are allowed for logical pointer types:

Change:

If OpVariable allocates an object whose type is or contains a logical pointer type, the Storage Class operand of the OpVariable must be one of the following:

  • Function

  • Private

To:

If a variable allocates an object whose type is or contains a logical pointer type, the Storage Class operand of the variable must be one of the following:

  • Function

  • Private

Change:

A pointer can be a variable pointer or an operand to one of:

  • OpPtrAccessChain

  • OpPtrEqual

  • OpPtrNotEqual

  • OpPtrDiff

To:

A pointer can be a variable pointer or an operand to one of:

Change:

The instructions OpPtrEqual and OpPtrNotEqual can be used only if the Storage Class of the operands OpTypePointer declaration:

To:

The instructions OpPtrEqual and OpPtrNotEqual can be used only if the Storage Class of the operands pointer type declaration:

Modify the list items under the following list item:

A variable pointer must not:

Change:

be an operand to an OpArrayLength instruction

To:

be an operand to an OpArrayLength or OpUntypedArrayLengthKHR instruction

Modify the list items under the following list item:

Physical Storage Buffer

Change:

OpVariable must not use the PhysicalStorageBuffer storage class.

To:

Variables must not use the PhysicalStorageBuffer storage class.

Change:

Any pointer value whose storage class is PhysicalStorageBuffer and that points to a matrix, an array of matrices, or a row or element of a matrix must be the result of an OpAccessChain or OpPtrAccessChain instruction whose Base operand is a structure type (or recursively must be the result of a sequence of only access chains from a structure to the final value). Such a pointer must only be used as the Pointer operand to OpLoad or OpStore.

To:

Any pointer value whose storage class is PhysicalStorageBuffer and that points to a matrix, an array of matrices, or a row or element of a matrix must be the result of an access chain instruction whose Base (or Base Type for untyped pointers) operand is a structure type (or recursively must be the result of a sequence of only access chains from a structure to the final value). Such a pointer must only be used as the Pointer operand to OpLoad or OpStore.

Modify the list items under the following list item:

Global (Module Scope) Variables

Change:

A module-scope OpVariable with an Initializer operand must not be decorated with the Import Linkage Type.

To:

A module-scope variable with an Initializer operand must not be decorated with the Import Linkage Type.

Changes list items under the following list item:

The capabilities StorageBuffer16BitAccess, UniformAndStorageBuffer16BitAccess, StoragePushConstant16, and StorageInputOutput16 do not generally add 16-bit operations. Rather, they add only the following specific abilities:

Change:

A structure containing a 16-bit member can be an operand to OpArrayLength.

To:

A structure containing a 16-bit member can be an operand to OpArrayLength or OpUntypedArrayLengthKHR.

Add the following list items:

Change list items under the following list item:

The capabilities StorageBuffer8BitAccess, UniformAndStorageBuffer8BitAccess, and StoragePushConstant8, do not generally add 8-bit operations. Rather, they add only the following specific abilities:

Change:

A structure containing a 8-bit member can be an operand to OpArrayLength.

To:

A structure containing a 8-bit member can be an operand to OpArrayLength or OpUntypedArrayLengthKHR.

Add the following list items:

Modify Section 2.16.2 Validation Rules for Shader Capabilities:

Add the following:

Modify the list items under the following list item:

Type Rules:

Change:

All declared types are restricted to those types that are, or are contained within, valid types for an OpVariable Result Type or an OpTypeFunction Return Type.

To:

All declared types are restricted to those types that are, or are contained within, valid types for an OpVariable Result Type, an OpUntypedVariableKHR Data Type, or an OpTypeFunction Return Type.

Change:

Aggregate types for intermediate objects are restricted to those types that are a valid Type of an OpVariable Result Type in the global storage classes.

To:

Aggregate types for intermediate objects are restricted to those types that are a valid Type of an OpVariable Result Type, or an OpUntypedVariableKHR Data Type in the global storage classes.

Modify Section 2.17 Universal Limits:

Change the table entry:

Indexes for OpAccessChain, OpInBoundsAccessChain, OpPtrAccessChain, OpInBoundsPtrAccessChain, OpCompositeExtract, and OpCompositeInsert

To:

Indexes for OpAccessChain, OpInBoundsAccessChain, OpPtrAccessChain, OpInBoundsPtrAccessChain, OpCompositeExtract, OpCompositeInsert, OpUntypedAccessChainKHR, OpUntypedInBoundsAccessChainKHR, OpUntypedPtrAccessChainKHR, and OpUntypedInBoundsPtrAccessChainKHR

Modify Section 2.18 Memory Model:

Change references to OpVariable to variable.

Add a new section at the end of Section 2 Specification titled Untyped Pointers:

OpTypePointer includes the data type of the memory that it points to as an operand of the type-declaration. Logical pointer types of type OpTypePointer are strongly typed. That is, the data they point to cannot be reinterpreted as another type in memory. Physical pointer types of type OpTypePointer are not strongly typed as OpBitcast can be used to cast from one representation to another. Unlike, OpTypePointer, OpTypeUntypedPointerKHR does not encode the type of data that it points to. This means that interpretation of the data type is left to instructions that utilize the pointer.

Each untyped instruction (OpUntyped…​) has an operand that specifies how the data should be interpreted (e.g. Base Type in OpUntypedAccessChainKHR). Also, OpUntypedAccessChainKHR, OpUntypedInBoundsAccessChainKHR, OpUntypedPtrAccessChainKHR, and OpUntypedInBoundsPtrAccessChainKHR may take either a typed or untyped pointer as the Base operand. This facilitates translations from high-level languages as it can localize where untyped pointers appear in syntax evaluation.

When memory accessed via instructions have a pointer operand with type OpTypeUntypedPointerKHR (e.g. OpLoad or atomic instructions), the interpreted data type is specified by the Result Type if it exists. The intepreted data type for instructions without a Result Type (e.g. OpStore) comes from the type of the operand of the object being stored. OpCopyMemorySized interprets the data as an array of 8-bit integers.

When an instruction accesses memory via an untyped pointer for storage class S and with interpreted data type T, the instruction behaves as if the pointer were of type OpTypePointer having Storage Class S and Type T. That is, the instruction will access exactly the same memory locations and interpret the data there as if using the corresponding strongly typed pointer.

Modify Section 3.7 Storage Class:

Add OpTypeUntypedPointerKHR and OpUntypedVariableKHR to the list of "Used by" instructions.

Modify Section 3.20 Decoration:

Change references to OpVariable to variable.

Modify Section 3.21 BuiltIn:

Change references to OpVariable to variable.

Modify Section 3.31 Capability:

Change references to OpTypePointer to pointer type.

Add the following rows to the table:

Capability Implicitly Declares

4473

UntypedPointersKHR

Enables the use of untyped pointers.

Modify Section 3.37 Instructions:

In the following instructions, change references to OpVariable to variable:

  • OpDecorateId

  • OpEntryPoint

  • OpTypeBool

  • OpSpecConstantOp

Add the following opcodes that are valid with the Kernel capability in OpSpecConstantOp:

Change the description of Result Type in OpImageTexelPointer to:

Result Type must be a pointer type whose Storage Class is Image. If it is an OpTypePointer type, its Type operand must be a numerical scalar type or OpTypeVoid.

Change the description of Image in OpImageTexelPointer to:

The type of Image must be a pointer type. If the type of Image is OpTypePointer:

  • It must point to an OpTypeImage.

  • The Sampled Type of the type of Image must be the same as the Type pointed to by Result Type.

  • The Dim operand of Type must not be SubpassData.

Change the description of Result Type in OpLoad to:

Result Type is the type of the loaded object. It must be a type with fixed size; i.e., it must not be, nor include, any OpTypeRuntimeArray types. If Pointer is required to be accessed with explicitly laid out types, then Result Type must also be explicitly laid out.

Change the description of Pointer in OpLoad to:

Pointer is the pointer to load through. Its type must be a pointer type. If its type is OpTypePointer, the Type operand must be the same as Result Type.

Change the description of Pointer in OpStore to:

Pointer is the pointer to store through. Its type must be a pointer type. If its type is OpTypePointer, the Type operand must be the same as the type of Object.

Change the description of Object in OpStore to:

Object is the object to store. If Pointer is required to be accessed with explicitly laid out types, then the type of Object must be explicitly laid out.

Change the description of OpCopyMemory to:

Copy from the memory pointed to by Source to the memory pointed to by Target. Both operands must be pointers and at least one must be an OpTypePointer type. If either Source or Target has type of OpTypePointer, the <id> Type operand must be non-void. If both Source and Target have a type of OpTypePointer, they must have the <id> Type operand. Matching Storage Class is not required. The amount of memory copied is the size of the type pointed to by an operand with a type of OpTypePointer. The copied type must have a fixed size; i.e., it must not be, nor include, any OpTypeRuntimeArray types.

If present, any Memory Operands must begin with a memory operand literal. If not present, it is the same as specifying the memory operand None. Before version 1.4, at most one memory operands mask can be provided. Starting with version 1.4 two masks can be provided, as described in Memory Operands. If no masks or only one mask is present, it applies to both Source and Target. If two masks are present, the first applies to Target and must not include MakePointerVisible, and the second applies to Source and must not include MakePointerAvailable.

Add the enabling capability UntypedPointersKHR to OpCopyMemorySized.

Change the restrictions on Operand 1 and Operand 2 in OpPtrEqual and OpPtrNotEqual to:

The Storage Class operand of the type of both Operand 1 and Operand 2 must match. If the types of Operand 1 and Operand 2 are OpTypePointer, they must be the same type.

Change the restriction on Operand 1 and Operand 2 in OpPtrDiff to:

The types of Operand 1 and Operand 2 must be the same OpTypePointer or OpTypeUntypedPointerKHR. If the types of Operand 1 and Operand 2 are OpTypePointer, they must point to a type that can be aggregated into an array. For an array of length L, Operand 1 and Operand 2 can point to any element in the range [0, L], where element L is outside the array but has a representative address computed with the same stride as elements in the array. Additionally, Operand 1 must be a valid Base operand of OpPtrAccessChain, OpUntypedPtrAccessChainKHR, OpInBoundsPtrAccessChain, or OpUntypedInBoundsPtrAccessChainKHR. Behavior is undefined if Operand 1 and Operand 2 are not pointers to element numbers in [0, L] in the same array. If Operand 1 and Operand 2 are OpTypeUntypedPointerKHR, the array is interpreted as an array of 8-bit integers.

Change the description of Result Type in OpPtrCastToGeneric to:

Result Type must be a pointer type. Its Storage Class must be Generic.

Change the description of OpGenericCastToPtr to:

Convert a pointer’s Storage Class to a non-Generic class.

Result Type must be a pointer type. Its Storage Class must be Workgroup, CrossWorkgroup, or Function.

Pointer must point to the Generic Storage Class.

If Result Type and the type of Pointer are OpTypePointer, they must point to the same type.

Change the description of OpGenericCastToPtrExplicit to:

Attempts to explicitly convert Pointer to Storage storage-class pointer value.

Result Type must be a pointer type. Its Storage Class must be Storage.

The type of Pointer must be a pointer type. Pointer must point to the Generic Storage Class. If the cast fails, the instruction result is an OpConstantNull pointer in the Storage Storage Class.

If Result Type and the type of Pointer are OpTypePointer, they must point to the same type.

Storage must be one of the following literal values from Storage Class: Workgroup, CrossWorkgroup, or Function.

Change the description of OpBitcast to:

Bit pattern-preserving type conversion.

Result Type must be a pointer type, or a scalar or vector of numerical-type.

The type of Operand must be a pointer type, or a scalar or vector of numerical-type. It must be a different type than Result Type.

Before version 1.5: If either Result Type or Operand is a pointer, the other must be a pointer or an integer scalar. Starting with version 1.5: If either Result Type or Operand is a pointer, the other must be a pointer, an integer scalar, or an integer vector.

If both Result Type and the type of Operand are pointers, they both must point into the same storage class.

Behaviour is undefined if the storage class of Result Type does not match the used by the operation that produced the value of Operand.

If Result Type has the same number of components as Operand, they must also have the same component width, and results are computed per component.

If Result Type has a different number of components than Operand, the total number of bits in Result Type must equal the total number of bits in Operand. Let L be the type, either Result Type or Operand’s type, that has the larger number of components. Let S be the other type, with the smaller number of components. The number of components in L must be an integer multiple of the number of components in S. The first component (that is, the only or lowest-numbered component) of S maps to the first components of L, and so on, up to the last component of S mapping to the last components of L. Within this mapping, any single component of S (mapping to multiple components of L) maps its lower-ordered bits to the lower-numbered components of L.

Change the description of Pointer in OpLifetimeStart and OpLifetimeStop to:

Pointer is a pointer to the object whose lifetime is starting/ending. Its type must be a pointer type with Storage Class Function.

Change the description of Pointer in OpAtomicLoad to:

Pointer is the pointer to the memory to read. Its type must be a pointer type. If its type is OpTypePointer, the type of the value pointed to by Pointer must be the same as Result Type.

Change the description of Pointer in OpAtomicStore to:

Pointer is the pointer to the memory to write. Its type must be a pointer type. If its type is OpTypePointer, the type it points to must be a scalar of integer type or floating-point type.

Change the description of Value in OpAtomicExchange to:

The type of Value must be the same as Result Type. The type of Pointer must be a pointer type. If it is OpTypePointer, the type of the value pointed to by Pointer must be the same as Result Type.

Change the description of Value in OpAtomicCompareExchange to:

The type of Value must be the same as Result Type. The type of Pointer must be a pointer type. If its type is OpTypePointer, the type of the value pointed to by Pointer must be the same as Result Type. This type must also match the type of Comparator.

Change the description of Value in OpAtomicIIncrement, OpAtomicIDecrement, OpAtomicIAdd, OpAtomicISub, OpAtomicSMin, OpAtomicUMin, OpAtomicSMax, OpAtomicUMax, OpAtomicAnd, OpAtomicOr, and OpAtomicXor to:

The type of Value must be the same as Result Type. The type of Pointer must be a pointer type. If its type is OpTypePointer, the type of the value pointed to by Pointer must be the same as Result Type.

Change the description of Pointer in OpAtomicFlagTestAndSet and OpAtomicFlagClear:

The type of Pointer must be a pointer type. If its type is OpTypePointer, it must point to a 32-bit integer type representing an atomic flag.

Add the following instruction to Section 3.37.6 Type-Declaration Instructions:

OpTypeUntypedPointerKHR

Declare a new pointer type. Similar to OpTypePointer, but does not require a pointee type.

Storage Class is the Storage Class of the memory holding object pointed to. Refer to the client API for allowed storage classes.

Capability:
UntypedPointersKHR

3

4417

Result <id>

Storage Class

Add the following instructions to Section 3.37.8 Memory Instructions:

OpUntypedVariableKHR

Allocate an object in memory, resulting in a pointer to it. Similar to OpVariable, but the allocated type is optionally provided via the Data Type operand instead via the pointee type of the Result Type.

Result Type must be an OpTypeUntypedPointerKHR.

Storage Class is the Storage Class of the memory holding the object. It must not be Generic. It must be the same storage class as the Storage Class operand of the Result Type.

Data Type is optional. It is the type of the object in memory. Data Type must be specified if Storage Class is Function, Private, or Workgroup. Refer to the client API for other storage classes. If Storage Class is required to be explicitly laid out, then Data Type must be explicitly laid out.

Initializer is optional. If Initializer is present, it will be the initial value of the variable’s memory content. Initializer must be an <id> from a constant instruction or a global (module scope) variable. Initializer must have the same type as Data Type.

Capability:
UntypedPointersKHR

5 + variable

4418

<id> Result Type

Result <id>

Storage Class

Optional <id> Data Type

Optional <id> Initializer

OpUntypedAccessChainKHR

Has the same semantics as OpAccessChain, with the following additions:
- Result Type must be an OpTypeUntypedPointerKHR. Its Storage Class operand must be the same Storage Class as Base.
- a Base Type operand. It must be a non-pointer type-declaration instruction. If Base is required to be accessed with explicitly laid out types, then Base Type must also be explicitly laid out. Base Type must not contain an array of structure type decorated with Block or BufferBlock unless Base is a variable whose data type is that array type. The data type of the Base variable must not contain an array of structure type decorated with Block or BufferBlock unless Base Type is that array type.
- the type of Base must be a pointer type.
- Indexes walk the type hierarchy of Base Type instead of Base.

Capability:
UntypedPointersKHR

5 + variable

4419

<id> Result Type

Result <id>

<id> Base Type

<id> Base

<id>, <id>, …​
Indexes

OpUntypedInBoundsAccessChainKHR

Has the same semantics as OpUntypedAccessChainKHR, with the addition that the resulting pointer is known to point within the base object.

Capability:
OpUntypedPointersKHR

5 + variable

4420

<id> Result Type

Result <id>

<id> Base Type

<id> Base

<id>, <id>, …​
Indexes

OpUntypedPtrAccessChainKHR

Has the same semantics as OpPtrAccessChain, with the following additions:
- Result Type must be an OpTypeUntypedPointerKHR. Its Storage Class operand must be the same Storage Class as Base.
- a Base Type operand. It must be a type-declaration instruction. If Base is required to be accessed with explicitly laid out types, then Base Type must also be explicitly laid out.
- the type of Base must be a pointer type. If the Storage Class is required to be explcitly laid out, then the type of Base must be decorated with ArrayStride.
- Element is used to generate an OpUntypedAccessChainKHR Base.
- Indexes walk the type hierarchy of Base Type instead of Base.

If Base Type is a structure decorated with Block or BufferBlock and the value of Element is not zero then behavior is undefined.

Capability: UntypedPointersKHR

6 + variable

4423

<id> Result Type

Result <id>

<id> Base Type

<id> Base

<id> Element

<id>, <id>, …​
Indexes

OpUntypedInBoundsPtrAccessChainKHR

Has the same semantics as OpUntypedPtrAccessChainKHR, with the addition that the resulting pointer is known to point within the base object.

Capability:
UntypedPointersKHR

6 + variable

4424

<id> Result Type

Result <id>

<id> Base Type

<id> Base

<id> Element

<id>, <id>, …​
Indexes

OpUntypedArrayLengthKHR

Length of a run-time array.

Result Type must be an OpTypeInt with 32-bit Width and 0 Signedness.

Structure must be an explcitly laid out Block-decorated OpTypeStruct whose last member is a run-time array.

The type of Pointer must be a pointer type. Pointer must have the same value as a descriptor. That is, the value must be the same as a variable decorated with DescriptorSet and Binding or an element in such a variable when the data type is an array of Block-decorated structures.

Array member is an unsigned 32-bit integer index of the last member of Structure. That member’s type must be from OpTypeRuntimeArray.

Capability:
UntypedPointersKHR

7

4425

<id> Result Type

Result <id>

<id> Structure

<id> Pointer

Literal Array member

OpUntypedPrefetchKHR

Prefetch Num Bytes bytes of data from Pointer into the global cache. This instruction does not affect the functionality of the module.

The type of Pointer must be a pointer whose Storage Class is CrossWorkgroup.

Num Bytes is the number of bytes to prefetch. Its type must be an integer scalar.

RW is optional. If RW is present, it specifies whether the fetch should be for a read or write. It must be a constant instruction with an integer scalar type. The value must be either 0 (for read) or 1 (for write).

Locality is optional. If Locality is present, it specifies the temporal locality for the caching. It must be a constant instruction with an integer scalar type. The value must be between 0 (for no locality) and 3 (for extreme locality) inclusive.

Cache Type is optional. If Cache Type is present, it specifies the type of cache. It must be a constant instruction with an integer scalar type. The value must be either 0 (for instruction cache) or 1 (for data cache).

The default values of all RW, Locality, and Cache Type operands are implementation defined.

If memory operands is specified, it must begin with a Memory Operand literal. If not present, it is the same as specifying Memory Operand None.

Either all optional operands must be specified or none must be specified.

Capability:
UntypedPointersKHR

4+

4426

<id> Pointer

<id> Num Bytes

Optional <id> RW

Optional <id> Locality

Optional <id> Cache Type

Optional memory operands

OpUntypedGroupAsyncCopyKHR
Perform an asynchronous group copy of Element Num Bytes × Num Elements bytes from Source to Destination. The asynchronous copy is performed by all invocations in a group.

This instruction results in an event object that can be used by OpGroupWaitEvents to wait for the async copy to finish.

Behavior is undefined unless all invocations within Execution execute the same dynamic instance of this instruction.

Result Type must be an OpTypeEvent object.

Destination must be a pointer of type OpUntypedPointerKHR.

Destination pointer Storage Class must be Workgroup or CrossWorkgroup.

Source must be a pointer of type OpUntypedPointerKHR.

If Destination pointer Storage Class is Workgroup, the Source pointer Storage Class must be CrossWorkgroup. In this case Stride defines the stride in bytes when reading from Source pointer.

If Destination pointer Storage Class is CrossWorkgroup, the Source pointer Storage Class must be Workgroup. In this case Stride defines the stride in bytes when writing each element to Destination pointer.

Stride, Num Bytes, and NumElements must be a 32-bit integer type scalar if the addressing model is Physical32 and 64 bit integer type scalar if the Addressing Model is Physical64.

Event must have a type of OpTypeEvent.

Event can be used to associate the copy with a previous copy allowing an event to be shared by multiple copies. Otherwise Event should be an OpConstantNull.

If Event is not OpConstantNull, the result is the event object supplied by the Event operand.

If present, Destination memory operands and Source memory operands must begin with a Memory Operand literal. If not present, it is the same as specifying the Memory Operand None. Either both memory operands must be specified or neither must be specified.

Capability:
UntypedPointersKHR

10+

4434

<id> Result Type

Result <id>

Scope <id> Execution

<id> Destination

<id> Source

<id> Element Num Bytes

<id> Num Elements

<id> Stride

<id> Event

Optional Destination memory operands

Optional Source memory operands

Modifications to the extension SPV_KHR_workgroup_memory_explicit_layout

Change:

If WorkgroupMemoryExplicitLayoutKHR capability is declared, for each entry point in the module

  • Either all or none of the Workgroup Storage Class variables in the entry point interface must point to struct types decorated with Block.

  • If more than one Workgroup Storage Class variable in the entry point interface point to a type decorated with Block, all of them must be decorated with Aliased.

To:

If WorkgroupMemoryExplicitLayoutKHR capability is declared, for each entry point in the module

  • Either all or none of the Workgroup Storage Class variables in the entry point interface must point to struct types decorated with Block.

  • If more than one Workgroup Storage Class variable in the entry point interface point to a type decorated with Block, all of them must be decorated with Aliased, unless the UntypedPointersKHR capability is declared. Only those variables decorated with Aliased may alias each other.

Change:

In addition to the above table, memory object declarations in the CrossWorkgroup, Function, Input, Output or Private storage classes must also have matching pointee types for aliasing to be present. The restriction also applies for Workgroup storage class, except when WorkgroupMemoryExplicitLayoutKHR capability is declared and the pointee types are structs decorated with Block. In all other cases the decoration is ignored.

To:

In addition to the above table, memory object declarations in the CrossWorkgroup, Function, Input, Output or Private storage classes must also have matching pointee types for aliasing to be present. The restriction also applies for Workgroup storage class, except when WorkgroupMemoryExplicitLayoutKHR capability is declared and the pointee types are structs decorated with Block or the pointer has the type OpTypeUntypedPointerKHR. In all other cases the decoration is ignored.

Modifications to the extension SPV_KHR_cooperative_matrix

In the descriptions of OpCooperativeMatrixLoadKHR and OpCooperativeMatrixStoreKHR change:

Pointer is a pointer. Its type must be an OpTypePointer whose Type operand is a scalar or vector type. If the Shader capability was declared, Pointer must point into an array and any ArrayStride decoration on Pointer is ignored.

To:

Pointer is a pointer. Its type must be a pointer type. If it is an OpTypePointer, its Type operand must be a scalar or vector type. If the Shader capability was declared and Pointer’s type is OpTypePointer, Pointer must point into an array and any ArrayStride decoration on Pointer is ignored.

And, change:

Stride further qualifies how matrix elements are laid out in memory. It must be a scalar integer type and its exact semantics depend on MemoryLayout.

To:

Stride further qualifies how matrix elements are laid out in memory. It must be a scalar integer type and its exact semantics depend on MemoryLayout. When the type of Pointer is OpTypePointer, Stride is specified in number of elements based on the Type operand of the pointer type. When the type of Pointer is OpTypeUntypedPointerKHR, Stride is specified in bytes.

Modifications to SPV_EXT_shader_float_atomic_add

In the description of OpAtomicFAddEXT, change:

The type of Value must be the same as Result Type. The type of the value pointed to by Pointer must be the same as Result Type.

To:

The type of Value must be the same as Result Type. If the type of Pointer is OpTypePointer, then type of the value it points to must be the same as Result Type.

Modifications to SPV_EXT_shader_float_atomic_min_max

In the description of OpAtomicFMaxEXT and OpAtomicFMinEXT, change:

The type of Value must be the same as Result Type. The type of the value pointed to by Pointer must be the same as Result Type.

To:

The type of Value must be the same as Result Type. If the type of Pointer is OpTypePointer, then type of the value it points to must be the same as Result Type.

Modifications to the OpenCL.std extended instruction set

Change the pointer naming conventions from:

  • pointer(storage) denotes an OpTypePointer which points to the storage Storage Class.

    • pointer(constant) denotes an OpTypePointer which points to the UniformConstant Storage Class.

    • pointer(generic) denotes an OpTypePointer which points to the Generic Storage Class.

    • pointer(global) denotes an OpTypePointer which points to the CrossWorkgroup Storage Class.

    • pointer(local) denotes an OpTypePointer which points to the Workgroup Storage Class.

    • pointer(private) denotes an OpTypePointer which points to the Function Storage Class.

To:

  • pointer(storage) denotes an OpTypePointer or OpTypeUntypedPointerKHR which points to the storage Storage Class.

    • pointer(constant) denotes an OpTypePointer or OpTypeUntypedPointerKHR which points to the UniformConstant Storage Class.

    • pointer(generic) denotes an OpTypePointer or OpTypeUntypedPointerKHR which points to the Generic Storage Class.

    • pointer(global) denotes an OpTypePointer or OpTypeUntypedPointerKHR which points to the CrossWorkgroup Storage Class.

    • pointer(local) denotes an OpTypePointer or OpTypeUntypedPointerKHR which points to the Workgroup Storage Class.

    • pointer(private) denotes an OpTypePointer or OpTypeUntypedPointerKHR which points to the Function Storage Class.

In the descriptions of the extended instructions, whenever a pointer operand is described as pointer(p1, p2, …​) to data types, split the sentence into two as follows:

operand must be a pointer(p1, …​). If it is a typed pointer, it must point to data types.

This applies to the following instructions:

  • ptr in fract

  • exp in frexp

  • signp in lgamma_r

  • iptr in modf

  • quo in remquo

  • cosval in sincos

  • p in vloadn

  • p in vstoren

  • p in vload_half

  • p in vload_halfn

  • p in vstore_half

  • p in vstore_half_r

  • p in vstore_halfn

  • p in vstore_halfn_r

  • p in vloada_halfn

  • p in vstorea_halfn

  • p in vstorea_halfn_r

  • format in printf

In the above instructions any type matching rule that applies to a pointee type is only applied to typed pointers. For untyped pointers, the instructions as if the it were an appropriate typed pointer.

Note: prefetch should be replaced with OpUntypedPrefetchKHR.

Issues

  1. Should this extension modify any other extensions?

    Resolved

    This extension modifies:

    • SPV_KHR_workgroup_memory_explicit_layout

    • SPV_KHR_cooperative_matrix

    • SPV_EXT_shader_atomic_float_add

    • SPV_EXT_shader_atomic_float_min_max

  2. Should this extension include pointer access chain equivalents?

    Resolved

    OpUntypedPtrAccessChainKHR and OpUntypedInBoundsPtrAccessChainKHR are not strictly necessary. OpUntypedAccessChainKHR (or OpUntypedInBoundsAccessChainKHR) could be used in place in all cases by changing the Base Type to be an array instead of just the element type; however, to simplify implementation transitions these instructions are included.

  3. Should this extension modify any extended instructions?

    Resolved

    This extension modifies the OpenCL.std extended instruction set. GLSL.std.450 is not modified as the interpolation instructions operate on the Input storage class and FrexpStruct and ModfStruct should be preferred to the version that utilize pointers.

Revision History

Rev

Date

Author

Changes

3

2025-01-16

Alan Baker

Changes from provisional.

Change reference SPIR-V Specification to Version 1.6 Revision 5.

Allow untyped pointer operands to the following instructions:

  • OpAtomicFAddEXT

  • OpAtomicFMaxEXT

  • OpAtomicFMinEXT

  • OpAtomicFlagTestAndSet

  • OpAtomicFlagClear

  • OpImageTexelPointer

Allow untyped access chains in OpSpecConstantOp.

Add memory operands to OpUntypedPrefetchKHR.

Add the instruction OpUntypedGroupAsyncCopyKHR.

Update physical storage buffer validation rules.

Restrict the use of arrays of blocks with untyped access chains.

2

2024-08-08

Kevin Petit

Clarify OpPtrDiff support

1

2024-05-29

Alan Baker

Initial Revision