KhronosGroup / SPIRV-Tools

Apache License 2.0
1.09k stars 559 forks source link

SPIR-V optimiser trimming needed capability StorageBuffer16BitAccess #5849

Open McDaMastR opened 1 month ago

McDaMastR commented 1 month ago

The SPIR-V optimiser spirv-opt includes the option --trim-capabilities, which should do the following.

Remove unnecessary capabilities and extensions declared within the module.

However, if the StorageBuffer16BitAccess capability is declared and used in a SPIR-V module, this optimisation removes it regardless. Here's the assembly of a module test.spvasm.

               OpCapability Shader
               OpCapability StorageBuffer16BitAccess
               OpMemoryModel Logical GLSL450
               OpEntryPoint GLCompute %main "main" %buffer
               OpExecutionMode %main LocalSize 1 1 1

               OpMemberDecorate %struct 0 Offset 0
               OpDecorate %struct Block

       %void = OpTypeVoid
       %func = OpTypeFunction %void
     %ushort = OpTypeInt 16 0
       %uint = OpTypeInt 32 0
     %uint_0 = OpConstant %uint 0
     %uint_1 = OpConstant %uint 1
     %struct = OpTypeStruct %ushort
 %ptr_ushort = OpTypePointer StorageBuffer %ushort
 %ptr_struct = OpTypePointer StorageBuffer %struct
     %buffer = OpVariable %ptr_struct StorageBuffer

       %main = OpFunction %void None %func
      %label = OpLabel
        %val =   OpUConvert %ushort %uint_1
        %ptr =   OpAccessChain %ptr_ushort %buffer %uint_0
                 OpStore %ptr %val
                 OpReturn
               OpFunctionEnd

This module converts a 32-bit unsigned value to 16-bit, and writes the result into a storage buffer. If you assemble this into SPIR-V 1.6,

spirv-as --target-env spv1.6 -o test.spv test.spvasm

then apply the --trim-capabilities optimisation,

spirv-opt --target-env=spv1.6 --trim-capabilities -o test2.spv test.spv

and then disassemble the optimised SPIR-V,

spirv-dis --no-header --nested-indent -o test2.spvasm test2.spv

you get the following assembly of the module test2.spvasm (minus some tidying up).

               OpCapability Shader
               OpMemoryModel Logical GLSL450
               OpEntryPoint GLCompute %1 "main" %2
               OpExecutionMode %1 LocalSize 1 1 1

               OpMemberDecorate %_struct_3 0 Offset 0
               OpDecorate %_struct_3 Block

       %void = OpTypeVoid
          %5 = OpTypeFunction %void
     %ushort = OpTypeInt 16 0
       %uint = OpTypeInt 32 0
     %uint_0 = OpConstant %uint 0
     %uint_1 = OpConstant %uint 1
  %_struct_3 = OpTypeStruct %ushort
%_ptr_StorageBuffer_ushort = OpTypePointer StorageBuffer %ushort
%_ptr_StorageBuffer__struct_3 = OpTypePointer StorageBuffer %_struct_3
          %2 = OpVariable %_ptr_StorageBuffer__struct_3 StorageBuffer

          %1 = OpFunction %void None %5
         %12 = OpLabel
         %13 =   OpUConvert %ushort %uint_1
         %14 =   OpAccessChain %_ptr_StorageBuffer_ushort %2 %uint_0
                 OpStore %14 %13
                 OpReturn
               OpFunctionEnd

The StorageBuffer16BitAccess capability has been removed, despite the module declaring the 16-bit integer type, converting a 32-bit integer value to 16-bit, and storing a 16-bit integer value into a storage buffer. This is also recognised by the SPIR-V validator, which when run on this module,

spirv-val --target-env spv1.6 test2.spv

gives the following output.

error: line 9: Using a 16-bit integer type requires the Int16 capability, or an extension that explicitly enables 16-bit integers.

%ushort = OpTypeInt 16 0

All SPIRV-Tools used (spirv-as, spirv-dis, spirv-opt, and spirv-val) give the following --version.

SPIRV-Tools v2024.4 v2024.4.rc1-0-g6dcc7e35