DirectXShaderCompiler
DirectXShaderCompiler copied to clipboard
[SPIR-V] Fatal error with validation on using bitfield uint64_t
Description
When using a shader with bitfield structs and uint64_t, getting invalid SPIR-V and failing.
Steps to Reproduce
For example, when using the following struct:
struct TransferRequest
{
// This represents a transfer command/request
uint64_t srcAddr;
uint64_t dstAddr;
uint64_t srcIndexAddr; // IOTA default
uint64_t dstIndexAddr; // IOTA default
uint64_t elementCount : 35; // allow up to 64GB IGPUBuffers
uint64_t propertySize : 24; // all the leftover bits (just use bytes now)
uint64_t fill;
// 0=uint8, 1=uint16, 2=uint32, 3=uint64
uint64_t srcIndexSizeLog2 : 2;
uint64_t dstIndexSizeLog2 : 2;
};
And trying to set values to it.
(Error happens on this shader code: https://github.com/Devsh-Graphics-Programming/Nabla/tree/adc4d576d034b3e1fb31356645c0a0915beee817/include/nbl/builtin/hlsl/property_pool)
Actual Behavior Invalid SPIR-V causing fatal error on validation.
fatal error: generated SPIR-V is invalid: [VUID-StandaloneSpirv-Base-04781] Expected 32-bit int type for Base operand: BitFieldInsert
%58 = OpBitFieldInsert %ulong %42 %57 %uint_0 %uint_35
Environment
- DXC version: From commit 7d2f9c74d53dcbb9de4e148b68c99e5986875be6
- Host Operating System: Windows 11 version 22H2 build 22621.3155
Minimal reproducible example: https://godbolt.org/z/86j5fcKGf
I think this might actually be a spirv-val error. If I'm reading https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpBitFieldInsert correctly OpBitFieldInsert is allowed to have a result type of any scalar or vector integer type, and base and insert must have the same type. There's nothing stating that it must have a specific bit width. I'll double check with some of the people who work on spirv-val.
Okay, so apparently SPIR-V allows it for OpenCL but not for Vulkan. Looks like we'll have to update DXC to split the 64-bit int into two 32-bit ints before doing OpBitFieldInsert.
Okay, so apparently SPIR-V allows it for OpenCL but not for Vulkan. Looks like we'll have to update DXC to split the 64-bit int into two 32-bit ints before doing
OpBitFieldInsert.
Strange cause GL allows any type https://registry.khronos.org/OpenGL-Refpages/gl4/html/bitfieldInsert.xhtml
Hello!
The limitation comes from Vulkan: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/StandaloneSpirv.html
VUID-StandaloneSpirv-Base-04781
The Base operand of any OpBitCount, OpBitReverse, OpBitFieldInsert, OpBitFieldSExtract, or OpBitFieldUExtract instruction must be a 32-bit integer scalar or a vector of 32-bit integers
We should be able to support uint64_t with some shifts/bitwise to extract a 32bit value to insert the field in.
oof, Vulkan cutting away regular OpenGL features strikes again!