Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPIRV code fails validation after optimization #5624

Open
pborsutzki opened this issue Mar 27, 2024 · 3 comments · May be fixed by #5684
Open

SPIRV code fails validation after optimization #5624

pborsutzki opened this issue Mar 27, 2024 · 3 comments · May be fixed by #5684

Comments

@pborsutzki
Copy link

Hi,

I built a shader in slang that fails validation on -O3, but does not on -O1. The slang team redirected me here as they think the problem comes from spirv-opt.

Compiling the slang code from the slang ticket gives me shader.spv spirv file on -O0, find it here: spirv_opt.zip.

Calling spirv-val shader.spv from the 1.3.280 vulkan sdk gives me no validation errors for this file.

Calling spirv-opt --validate-after-all -O shader.spv -o shaderOpt.spv results in this validation error:

error: line 124: Expected Constituent type to be equal to the corresponding member type of Result Type struct
  %92 = OpCompositeConstruct %Bar %88 %121

error: line 0: Validation failed after pass simplify-instructions

Can you fix this issue or point me to a workaround? Thanks!

@cassiebeckley
Copy link
Contributor

Minimal reproducible example:

; SPIR-V
; Version: 1.5
; Generator: Khronos; 40
; Bound: 91
; Schema: 0
               OpCapability Int64
               OpCapability VariablePointers
               OpCapability PhysicalStorageBufferAddresses
               OpCapability Shader
               OpExtension "SPV_KHR_storage_buffer_storage_class"
               OpExtension "SPV_KHR_variable_pointers"
               OpExtension "SPV_KHR_physical_storage_buffer"
               OpMemoryModel PhysicalStorageBuffer64 GLSL450
               OpEntryPoint GLCompute %2 "main"
               OpExecutionMode %2 LocalSize 1 1 1
               OpMemberDecorate %structA 0 Offset 0
               OpMemberDecorate %structB 0 Offset 0
               OpMemberDecorate %structC 0 Offset 0
       %void = OpTypeVoid
          %3 = OpTypeFunction %void
      %ulong = OpTypeInt 64 0
 %structA = OpTypeStruct %ulong
 %structB = OpTypeStruct %ulong
 %structC = OpTypeStruct %structB
         %90 = OpUndef %structA
          %2 = OpFunction %void None %3
          %4 = OpLabel
         %45 = OpCompositeExtract %ulong %90 0
         %40 = OpCompositeConstruct %structB %45
         %34 = OpCompositeConstruct %structC %40
               OpReturn
               OpFunctionEnd

@cassiebeckley
Copy link
Contributor

cassiebeckley commented Mar 27, 2024

Before and after simplify-instructions:

; IR before pass simplify-instructions
OpCapability Int64
OpCapability VariablePointers
OpCapability PhysicalStorageBufferAddresses
OpCapability Shader
OpExtension "SPV_KHR_storage_buffer_storage_class"
OpExtension "SPV_KHR_variable_pointers"
OpExtension "SPV_KHR_physical_storage_buffer"
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint GLCompute %1 "main"
OpExecutionMode %1 LocalSize 1 1 1
OpMemberDecorate %_struct_2 0 Offset 0
OpMemberDecorate %_struct_3 0 Offset 0
OpMemberDecorate %_struct_4 0 Offset 0
%void = OpTypeVoid
%6 = OpTypeFunction %void
%ulong = OpTypeInt 64 0
%_struct_2 = OpTypeStruct %ulong
%_struct_3 = OpTypeStruct %ulong
%_struct_4 = OpTypeStruct %_struct_3
%8 = OpUndef %_struct_2
%1 = OpFunction %void None %6
%9 = OpLabel
%10 = OpCompositeExtract %ulong %8 0
%11 = OpCompositeConstruct %_struct_3 %10
%12 = OpCompositeConstruct %_struct_4 %11
OpReturn
OpFunctionEnd

; IR before pass scalar-replacement=100
OpCapability Int64
OpCapability VariablePointers
OpCapability PhysicalStorageBufferAddresses
OpCapability Shader
OpExtension "SPV_KHR_storage_buffer_storage_class"
OpExtension "SPV_KHR_variable_pointers"
OpExtension "SPV_KHR_physical_storage_buffer"
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint GLCompute %1 "main"
OpExecutionMode %1 LocalSize 1 1 1
OpMemberDecorate %_struct_2 0 Offset 0
OpMemberDecorate %_struct_3 0 Offset 0
OpMemberDecorate %_struct_4 0 Offset 0
%void = OpTypeVoid
%6 = OpTypeFunction %void
%ulong = OpTypeInt 64 0
%_struct_2 = OpTypeStruct %ulong
%_struct_3 = OpTypeStruct %ulong
%_struct_4 = OpTypeStruct %_struct_3
%8 = OpUndef %_struct_2
%1 = OpFunction %void None %6
%9 = OpLabel
%10 = OpCompositeExtract %ulong %8 0
%12 = OpCompositeConstruct %_struct_4 %8
OpReturn
OpFunctionEnd

@cassiebeckley cassiebeckley self-assigned this Mar 27, 2024
@s-perron
Copy link
Collaborator

This look like an issues with the isomorphic structs. This confuses the type manager when the type manager is not used correctly. This is a known source of bugs, but there is not enough activity on spirv-opt to make a major change to the type manager.

I'll try fixing the code in this one place, and check if I can add an assert that might catch some of these cases. Assuming my guess at the root cause is correct.

@s-perron s-perron self-assigned this May 22, 2024
s-perron added a commit to s-perron/SPIRV-Tools that referenced this issue May 22, 2024
When dealing with structs the type manager merge two different structs
into a single entry if they have all of the same decorations and
element types. This is because they hash to the same value in the hash
table. This can cause problems if you need to get the id of a type from
the type manager because you could get either one. In this case, it
returns the wrong one.

The fix is to avoid using the type manager in certain places. I have not
looked closely at all of the places the type manager is used to make
sure it is used safely everywhere else.

Fixes KhronosGroup#5624
s-perron added a commit to s-perron/SPIRV-Tools that referenced this issue May 23, 2024
When dealing with structs the type manager merge two different structs
into a single entry if they have all of the same decorations and
element types. This is because they hash to the same value in the hash
table. This can cause problems if you need to get the id of a type from
the type manager because you could get either one. In this case, it
returns the wrong one.

The fix avoids using the type manager in one place. I have not
looked closely at other places the type manager is used to make
sure it is used safely everywhere.

Fixes KhronosGroup#5624
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants