KhronosGroup / KhronosGroup/SPIRV-Tools

[spirv-opt] validation failure in spirv-opt eliminate-dead-code-aggressive on slang shader

Open
#6,365 1 comment 0 reactions 0 assignees View on GitHub
component:optimization
Dominant language
C++
Stars
1.4k
Forks
709
Avg merge
1d 22h
Merged PRs (30d)
28

Description

```slang
struct Constants {
uint2 tile_resolution;
uint *tile_buffer;
}

[shader("compute")]
[numthreads(8, 8, 1)]
void main(uniform Constants constants, uint3 group_id: SV_GroupID) {
let tile_coord = group_id.xy * WorkgroupSize().xy;
// Uncomment this and it will compile fine:
// let hi = constants.tile_buffer[tile_coord.x];
}
```

compiled with the following command on current main (https://github.com/shader-slang/slang/commit/7e35123bae1cd3b032fdffcafd600aa78394bf2d)

```
$ slangc test.slang -target spirv -profile spirv_1_6 -capability vk_mem_model -fvk-use-scalar-layout -fvk-use-entrypoint-name -matrix-layout -row-major -O0 -g -o test.spv
```

produces spirv which passes spirv-val, however, spirv-opt fails validation during a dce pass.

```
$ spirv-opt --validate-after-all -O test.spv -o test-opt.spv
error: line 115: ID '85[%85]' has not been defined
%137 = OpCompositeExtract %v2uint %85 0

error: line 0: Validation failed after pass eliminate-dead-code-aggressive
```

where spirv-opt is `SPIRV-Tools v2025.4 v2025.4-0-g7f2d9ee92`

the spirv generated is as follows

```spirv
; SPIR-V
; Version: 1.6
; Generator: Khronos Slang Compiler; 0
; Bound: 102
; Schema: 0
OpCapability PhysicalStorageBufferAddresses
OpCapability Shader
OpCapability VulkanMemoryModel
OpCapability VulkanMemoryModelDeviceScope
OpExtension "SPV_KHR_non_semantic_info"
OpExtension "SPV_KHR_physical_storage_buffer"
OpExtension "SPV_KHR_vulkan_memory_model"
%2 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
OpMemoryModel PhysicalStorageBuffer64 Vulkan
OpEntryPoint GLCompute %main "main" %entryPointParams %gl_WorkGroupID
OpExecutionMode %main LocalSize 8 8 1
%1 = OpString "struct Constants {
uint2 tile_resolution;
uint *tile_buffer;
}

[shader(\"compute\")]
[numthreads(8, 8, 1)]
void main(uniform Constants constants, uint3 group_id: SV_GroupID) {
let tile_coord = group_id.xy * WorkgroupSize().xy;
// Uncomment this and it will compile fine:
// let hi = constants.tile_buffer[tile_coord.x];
}
"
%5 = OpString "/home/josh/Projects/narcissus/test.slang"
OpSource Slang 1
%27 = OpString "main"
%33 = OpString "slangc"
%34 = OpString "-target spirv -I \"/home/josh/Projects/slang/build/Debug/bin\" -fvk-use-entrypoint-name -matrix-layout-row-major -O0 -capability vk_mem_model -force-glsl-scalar-layout -stage compute -entry main -g2"
%36 = OpString "uint"
%42 = OpString "group_id"
%52 = OpString "tile_resolution"
%58 = OpString "tile_buffer"
%60 = OpString "Constants"
%63 = OpString "constants"
%72 = OpString "Constants_natural"
%75 = OpString "EntryPointParams_natural"
%77 = OpString "entryPointParams"
%98 = OpString "tile_coord"
OpName %_dbgvar_group_id "_dbgvar_group_id"
OpName %Constants "Constants"
OpMemberName %Constants 0 "tile_resolution"
OpMemberName %Constants 1 "tile_buffer"
OpName %_dbgvar_constants "_dbgvar_constants"
OpName %_dbgvar_tile_coord "_dbgvar_tile_coord"
OpName %group_id "group_id"
OpName %constants "constants"
OpName %Constants_natural "Constants_natural"
OpMemberName %Constants_natural 0 "tile_resolution"
OpMemberName %Constants_natural 1 "tile_buffer"
OpName %EntryPointParams_natural "EntryPointParams_natural"
OpMemberName %EntryPointParams_natural 0 "constants"
OpName %entryPointParams "entryPointParams"
OpName %tile_coord "tile_coord"
OpName %main "main"
OpDecorate %_ptr_PhysicalStorageBuffer_uint ArrayStride 4
OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
OpMemberDecorate %Constants_natural 0 Offset 0
OpMemberDecorate %Constants_natural 1 Offset 8
OpDecorate %EntryPointParams_natural Block
OpMemberDecorate %EntryPointParams_natural 0 Offset 0
%void = OpTypeVoid
%4 = OpExtInst %void %2 DebugSource %5 %1
%uint = OpTypeInt 32 0
%uint_11 = OpConstant %uint 11
%uint_5 = OpConstant %uint 5
%uint_100 = OpConstant %uint 100
%10 = OpExtInst %void %2 DebugCompilationUnit %uint_100 %uint_5 %4 %uint_11
%12 = OpTypeFunction %void
%v3uint = OpTypeVector %uint 3
%_ptr_Function_v3uint = OpTypePointer Function %v3uint
%v2uint = OpTypeVector %uint 2
%_ptr_PhysicalStorageBuffer_uint = OpTypePointer PhysicalStorageBuffer %uint
%Constants = OpTypeStruct %v2uint %_ptr_PhysicalStorageBuffer_uint
%_ptr_Function_Constants = OpTypePointer Function %Constants
%_ptr_Function_v2uint = OpTypePointer Function %v2uint
%uint_0 = OpConstant %uint 0
%24 = OpExtInst %void %2 DebugTypeFunction %uint_0 %void
%uint_8 = OpConstant %uint 8
%uint_6 = OpConstant %uint 6
%26 = OpExtInst %void %2 DebugFunction %27 %24 %4 %uint_8 %uint_6 %10 %27 %uint_0 %uint_8
%32 = OpExtInst %void %2 DebugEntryPoint %26 %10 %33 %34
%uint_32 = OpConstant %uint 32
%uint_131072 = OpConstant %uint 131072
%35 = OpExtInst %void %2 DebugTypeBasic %36 %uint_32 %uint_6 %uint_131072
%uint_3 = OpConstant %uint 3
%39 = OpExtInst %void %2 DebugTypeVector %35 %uint_3
%uint_2 = OpConstant %uint 2
%group_id = OpExtInst %void %2 DebugLocalVariable %42 %39 %4 %uint_8 %uint_6 %26 %uint_0 %uint_2
%44 = OpExtInst %void %2 DebugExpression
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
%50 = OpExtInst %void %2 DebugTypeVector %35 %uint_2
%uint_1 = OpConstant %uint 1
%uint_64 = OpConstant %uint 64
%51 = OpExtInst %void %2 DebugTypeMember %52 %50 %4 %uint_1 %uint_8 %uint_0 %uint_64 %uint_0
%uint_5349 = OpConstant %uint 5349
%55 = OpExtInst %void %2 DebugTypePointer %35 %uint_5349 %uint_131072
%57 = OpExtInst %void %2 DebugTypeMember %58 %55 %4 %uint_1 %uint_8 %uint_64 %uint_64 %uint_0
%uint_128 = OpConstant %uint 128
%59 = OpExtInst %void %2 DebugTypeComposite %60 %uint_1 %4 %uint_1 %uint_8 %10 %60 %uint_128 %uint_131072 %51 %57
%constants = OpExtInst %void %2 DebugLocalVariable %63 %59 %4 %uint_8 %uint_6 %26 %uint_0 %uint_1
%Constants_natural = OpTypeStruct %v2uint %_ptr_PhysicalStorageBuffer_uint
%EntryPointParams_natural = OpTypeStruct %Constants_natural
%_ptr_PushConstant_EntryPointParams_natural = OpTypePointer PushConstant %EntryPointParams_natural
%69 = OpExtInst %void %2 DebugTypeMember %52 %50 %4 %uint_0 %uint_0 %uint_0 %uint_64 %uint_0
%70 = OpExtInst %void %2 DebugTypeMember %58 %55 %4 %uint_0 %uint_0 %uint_64 %uint_64 %uint_0
%71 = OpExtInst %void %2 DebugTypeComposite %72 %uint_1 %4 %uint_0 %uint_0 %10 %72 %uint_128 %uint_131072 %69 %70
%73 = OpExtInst %void %2 DebugTypeMember %63 %71 %4 %uint_0 %uint_0 %uint_0 %uint_128 %uint_0
%74 = OpExtInst %void %2 DebugTypeComposite %75 %uint_1 %4 %uint_0 %uint_0 %10 %75 %uint_128 %uint_131072 %73
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_PushConstant_Constants_natural = OpTypePointer PushConstant %Constants_natural
%uint_9 = OpConstant %uint 9
%v2int = OpTypeVector %int 2
%int_8 = OpConstant %int 8
%94 = OpConstantComposite %v2int %int_8 %int_8
%tile_coord = OpExtInst %void %2 DebugLocalVariable %98 %50 %4 %uint_9 %uint_9 %26 %uint_0
%gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input
%entryPointParams = OpVariable %_ptr_PushConstant_EntryPointParams_natural PushConstant
%76 = OpExtInst %void %2 DebugGlobalVariable %77 %74 %4 %uint_0 %uint_0 %10 %77 %entryPointParams %uint_0
%main = OpFunction %void None %12
%13 = OpLabel
%_dbgvar_group_id = OpVariable %_ptr_Function_v3uint Function
%_dbgvar_constants = OpVariable %_ptr_Function_Constants Function
%_dbgvar_tile_coord = OpVariable %_ptr_Function_v2uint Function
%30 = OpExtInst %void %2 DebugFunctionDefinition %26 %main
%31 = OpExtInst %void %2 DebugScope %26
%45 = OpExtInst %void %2 DebugDeclare %group_id %_dbgvar_group_id %44
%46 = OpLoad %v3uint %gl_WorkGroupID
OpStore %_dbgvar_group_id %46
%64 = OpExtInst %void %2 DebugDeclare %constants %_dbgvar_constants %44
%81 = OpAccessChain %_ptr_PushConstant_Constants_natural %entryPointParams %int_0
%82 = OpLoad %Constants_natural %81
%83 = OpCompositeExtract %v2uint %82 0
%84 = OpCompositeExtract %_ptr_PhysicalStorageBuffer_uint %82 1
%85 = OpCompositeConstruct %Constants %83 %84
OpStore %_dbgvar_constants %85
%87 = OpLoad %v3uint %gl_WorkGroupID
%88 = OpExtInst %void %2 DebugLine %4 %uint_9 %uint_9 %uint_5 %uint_6
%90 = OpExtInst %void %2 DebugLine %4 %uint_9 %uint_9 %uint_5 %uint_6
%91 = OpVectorShuffle %v2uint %87 %87 0 1
%92 = OpBitcast %v2uint %94
%96 = OpIMul %v2uint %91 %92
%99 = OpExtInst %void %2 DebugDeclare %tile_coord %_dbgvar_tile_coord %44
OpStore %_dbgvar_tile_coord %96
OpReturn
OpFunctionEnd
```

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the failure with the supplied test.slang, slangc command, and spirv-opt --validate-after-all -O invocation. Inspect the eliminate-dead-code-aggressive pass using the generated SPIR-V around the undefined %85 and verify that optimization completes with validation enabled and produces valid output.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.