KhronosGroup / glslang

Khronos-reference front end for GLSL/ESSL, partial front end for HLSL, and a SPIR-V generator.
Other
3.05k stars 836 forks source link

Expressions in specialization constants #3748

Open taniwha opened 1 month ago

taniwha commented 1 month ago

Both glslang and glslangValidator compile the following code without any diagnostics

#version 450 core

layout(constant_id = 0) const int baz = 1;
layout(constant_id = 1) const int buz = baz + 1;

void main () { }

And produce

; SPIR-V
; Version: 1.6
; Generator: Khronos Glslang Reference Front End; 11
; Bound: 10
; Schema: 0
               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Vertex %main "main"
               OpSource GLSL 450
               OpName %main "main"
               OpName %baz "baz"
               OpName %buz "buz"
               OpDecorate %baz SpecId 0
               OpDecorate %buz SpecId 1
       %void = OpTypeVoid
          %3 = OpTypeFunction %void
        %int = OpTypeInt 32 1
        %baz = OpSpecConstant %int 1
      %int_1 = OpConstant %int 1
        %buz = OpSpecConstantOp %int IAdd %baz %int_1
       %main = OpFunction %void None %3
          %5 = OpLabel
               OpReturn
               OpFunctionEnd

but spirv-val produces the following error:

error: line 10: SpecId decoration on target <id> '9[%buz]' must be a scalar specialization constant
  OpDecorate %buz SpecId 1

The spec (2.12) does seem to indicate that spirv-val is correct and glslanValidator is producing incorrect code.

arcady-lunarg commented 1 month ago

What semantics are you expecting from this GLSL? Just going by SPIR-V semantics, it seems like this shouldn't be legal, as you are giving a specialization constant a default value that's not a simple constant, which SPIR-V does not support.

The GLSL spec does say

Initializers for const declarations must be constant expressions, as defined in section 4.3.3 “Constant Expressions."

And the GL_KHR_vulkan_glsl spec says

An expression formed with specialization constants also behaves in the shader like a specialization constant, not a like a constant.

So it seems like the logical thing would be for glslang to prohibit this type of expression.

taniwha commented 1 month ago

What semantics are you expecting from this GLSL? Just going by SPIR-V semantics, it seems like this shouldn't be legal, as you are giving a specialization constant a default value that's not a simple constant, which SPIR-V does not support.

My only expectation is consistency between the tools. And maybe less reading between the lines in the specs, but that is probably for a separate issue or two.

I ran into the problem due to implementing SPIR-V in my compiler. I'd written such code as a test (to confirm my understanding of the specifications) and because glslang accepted it, I assumed it was OK (I didn't think to run its output through spirv-val), but when my own compiler's output failed, I went back to glslang to see what I had done and discovered it too failed. After rereading the relevant parts of both specs (GLSL doesn't seem to be explicit about requiring a literal) I decided to file the issue against glslang.

So it seems like the logical thing would be for glslang to prohibit this type of expression.

I agree. I did this in my compiler as it seemed I was asking the impossible from SPIR-V.