KhronosGroup / KhronosGroup/glslang

Nonliteral [[vk::constant_id]] generates standard constant

Open
#1,773 1 comment 0 reactions 0 assignees View on GitHub
bug HLSL sev:miscompile
Dominant language
C++
Stars
3.6k
Forks
989
Avg merge
1d 2h
Merged PRs (30d)
31

Description

I am attempting to compile the following code:

```HLSL
static int NEXT_SPEC_CONST_ID = 0;

[[vk::constant_id(NEXT_SPEC_CONST_ID++)]] const float TEST_FLOAT_1 = 0.32f;
[[vk::constant_id(NEXT_SPEC_CONST_ID++)]] const float TEST_FLOAT_2 = 0.33f;

struct VS_INPUT
{
float4 pos : POSITION;
};

struct VS_OUTPUT
{
float4 pos : SV_POSITION;
};

VS_OUTPUT main( const VS_INPUT input )
{
VS_OUTPUT output;
output.pos = input.pos;
output.pos.x *= TEST_FLOAT_1;
output.pos.y *= TEST_FLOAT_2;
return output;
}
```

I'm reasonably certain this isn't allowed. However in that case, I'd expect it to give me a compiler error, rather than silently demoting the specialization constants to regular constants:

```SPIR-V
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 7
; Bound: 84
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %input_pos %_entryPointOutput_pos
OpSource HLSL 500
OpName %main "main"
OpName %input_pos "input.pos"
OpName %_entryPointOutput_pos "@entryPointOutput.pos"
OpDecorate %input_pos Location 0
OpDecorate %_entryPointOutput_pos BuiltIn Position
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%float_0_319999993 = OpConstant %float 0.319999993
%float_0_330000013 = OpConstant %float 0.330000013
%_ptr_Input_v4float = OpTypePointer Input %v4float
%input_pos = OpVariable %_ptr_Input_v4float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput_pos = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
%44 = OpLoad %v4float %input_pos
%56 = OpCompositeExtract %float %44 0
%57 = OpFMul %float %56 %float_0_319999993
%80 = OpCompositeInsert %v4float %57 %44 0
%60 = OpCompositeExtract %float %44 1
%61 = OpFMul %float %60 %float_0_330000013
%83 = OpCompositeInsert %v4float %61 %80 1
OpStore %_entryPointOutput_pos %83
OpReturn
OpFunctionEnd
```

If the IDs for the specialization constants are changed to literals, the codegen is correct:

```HLSL
...
[[vk::constant_id(2)]] const float TEST_FLOAT_1 = 0.32f;
[[vk::constant_id(5)]] const float TEST_FLOAT_2 = 0.33f;
...
```

```SPIR-V
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 7
; Bound: 84
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %input_pos %_entryPointOutput_pos
OpSource HLSL 500
OpName %main "main"
OpName %TEST_FLOAT_1 "TEST_FLOAT_1"
OpName %TEST_FLOAT_2 "TEST_FLOAT_2"
OpName %input_pos "input.pos"
OpName %_entryPointOutput_pos "@entryPointOutput.pos"
OpDecorate %TEST_FLOAT_1 SpecId 2
OpDecorate %TEST_FLOAT_2 SpecId 5
OpDecorate %input_pos Location 0
OpDecorate %_entryPointOutput_pos BuiltIn Position
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%TEST_FLOAT_1 = OpSpecConstant %float 0.319999993
%TEST_FLOAT_2 = OpSpecConstant %float 0.330000013
%_ptr_Input_v4float = OpTypePointer Input %v4float
%input_pos = OpVariable %_ptr_Input_v4float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput_pos = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
%44 = OpLoad %v4float %input_pos
%56 = OpCompositeExtract %float %44 0
%57 = OpFMul %float %56 %TEST_FLOAT_1
%80 = OpCompositeInsert %v4float %57 %44 0
%60 = OpCompositeExtract %float %44 1
%61 = OpFMul %float %60 %TEST_FLOAT_2
%83 = OpCompositeInsert %v4float %61 %80 1
OpStore %_entryPointOutput_pos %83
OpReturn
OpFunctionEnd
```

Contributor guide

Open the contributing guide

Research direction

Reproduce the issue using the HLSL examples and inspect the generated SPIR-V for literal versus nonliteral vk::constant_id values. Start by tracing the compiler path that handles vk::constant_id and compare its behavior with the shown OpConstant and OpSpecConstant output. Done means nonliteral IDs no longer silently become regular constants, with the intended diagnostic or behavior covered by a regression test.

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
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.