shader-slang / slang

Making it easier to work with shaders
MIT License
1.78k stars 159 forks source link

`unsigned int` does not work (Reprised) #4458

Open chaoticbob opened 5 days ago

chaoticbob commented 5 days ago

I see that #488 was closed as completed. However, it doesn't look unsigned int works. The below shader results in the following error message when unsigned is used with int:

shader.hlsl(26): error 20001: unexpected identifier, expected ';'
unsigned int main(unsigned int input: SV_InstanceID) : SV_InstanceID {
             ^~~~
shader.hlsl(26): error 20001: unexpected identifier, expected ')'
unsigned int main(unsigned int input: SV_InstanceID) : SV_InstanceID {
                           ^~~
shader.hlsl(26): error 20001: unexpected '{', expected ';'
unsigned int main(unsigned int input: SV_InstanceID) : SV_InstanceID {
                                                                     ^

Initially, I thought it may have something to do with where it's used, so I removed unsigned from the entry point signature, I get the same error for unsigned int x = 0:

shader.hlsl(27): error 20001: unexpected identifier, expected ';'
    unsigned int x = 0;

CMD

slangc.exe -target spirv -lang slang -D__spirv__ -emit-spirv-directly -profile vs_6_0 -entry main shader.hlsl

Shader

unsigned int main(unsigned int input: SV_InstanceID) : SV_InstanceID {
    unsigned int x = 0;
    return input + x;
}
jkwak-work commented 1 day ago

It turned out that unsigned is not a supported keyword for neither HLSL nor GLSL. Slang reserved the keyword but currently it is not a supported keyword.

The following HLSL shader is used for the testing,

RWStructuredBuffer<int > outputBuffer_0 : register(u0);

[numthreads(1, 1, 1)]
void computeMain(uint3 dispatchThreadID_0 : SV_DispatchThreadID)
{
    unsigned int idx_0 = unsigned int(dispatchThreadID_0.x);
    outputBuffer_0[idx_0] = dot(int3(idx_0 + int(1), idx_0 + int(2), idx_0 + int(3)), int3(int(1), int(2), int(3)));
    return;
}

It resulted in a following error,

a.hlsl:6:26: error: 'unspecified' cannot be signed or unsigned
    unsigned int idx_0 = unsigned int(dispatchThreadID_0.x);
                         ^
a.hlsl:6:35: error: expected '(' for function-style cast or type construction
    unsigned int idx_0 = unsigned int(dispatchThreadID_0.x);
                         ~~~~~~~~ ^

The following GLSL shader is used for the testing,

#version 450
layout(row_major) uniform;
layout(row_major) buffer;
layout(std430, binding = 0) buffer StructuredBuffer_int_t_0 {
    int _data[];
} outputBuffer_0;

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main()
{
    unsigned int idx_0 = unsigned int(gl_GlobalInvocationID.x);
    outputBuffer_0._data[idx_0] = int(dot(vec3(idx_0 + 1, idx_0 + 2, idx_0 + 3), vec3(1, 2, 3)));
    return;
}

It resulted in a following error,

ERROR: 0:11: 'unsigned' : Reserved word.
ERROR: 0:11: '' : compilation terminated
ERROR: 2 compilation errors.  No code generated.
jkwak-work commented 1 day ago

I suggest WNF for now and keep track it as a long term issue. @swoods-nv for a visibility.

jkwak-work commented 1 day ago

I like to leave a short note about what I learned while trying to implement this. I concur the observation from the previous attempt.

There are two ways to treat unsigned.

The first approach is to handle two tokens as a type. Parser will read one more token when the type token is "unsigned". This requires refactorying in a type DeclRefExpr.

class DeclRefExpr: public Expr
{
    Name* name = nullptr; // <== This needs to be changed to "List<Name*> name" or at least "Name* name[2]"

This seems an overkill for a rare case when "unsigned int" hasn't been used until now.

The second approach is to treat the keyword unsigned as a modifier. This defers the handling of unsigned from parser to semantic pass. I didn't go down this path much but this seemed equally overkill with added complexities to the semantic pass.