microsoft / DirectXShaderCompiler

This repo hosts the source for the DirectX Shader Compiler which is based on LLVM/Clang.
Other
2.99k stars 671 forks source link

[SPIR-V] Empty groupshared arrays generate invalid SPIR-V #3667

Open RossNordby opened 3 years ago

RossNordby commented 3 years ago

Using 0 as a constant value for a groupshared array causes a fatal error: generated SPIR-V is invalid: OpTypeArray Length <id> '11[%uint_0]' default value must be at least 1: found 0

Not exactly a big concern, but by request of the compiler output message, here's a reproduction:

RWByteAddressBuffer SomeBytes : register(u0);

groupshared int PoorlySizedArray[0];

[numthreads(1, 1, 1)]
void CSMain(uint3 threadId : SV_DispatchThreadID)
{ 
    SomeBytes.Store(threadId.x, PoorlySizedArray[threadId.x]);
}

Observed in 1.6.0.2994 and 1.6.0.3105 (1f6d1facb).

jaebaek commented 3 years ago

@RossNordby Thank you for reporting this issue. We will take a look.

cassiebeckley commented 1 year ago

@pow2clk is it valid HLSL for an array to have a size of zero? I found https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-syntax#name_index_ which seems to say that the array size should be equal to zero, unless I'm misreading it. Is that a typo?

pow2clk commented 1 year ago

Hi Cassie!

It is valid, but it was introduced somewhat unceremoniously. Initially it was a regression from FXC, which forbade this, but ultimately, we chose to make it official since the restriction no longer made sense. See #2461.

I think you are referring to this part of the documentation?

Name[Index]

ASCII string that uniquely identifies a shader variable. To define an optional array, use index for the array size, which is a positive integer = 1.

I think perhaps you meant to say that the array size should be equal to one? That's true and I fear it's not so much a typo as outdated documentation, which is something we are working on. However setting it to one should still work for these purposes, but zeros are allowed now too.

Keenuts commented 3 months ago

Looked at it a bit today. Looking at https://learn.microsoft.com/en-us/windows/win32/direct3d12/resource-binding-in-hlsl, seems like this should be handled as an array of unknown size.

The exact example in this document could be handled the codegen today (need to declare it as an OpRuntimeArray and some fixes around, but almost works)

Texture2D<float4> tex1[0] : register(t0);

[numthreads(1, 1, 1)]
void main(uint3 threadId : SV_DispatchThreadID)
{}

Same for:

Buffer<float4> buff[0];

cbuffer buffer {
    int array[0]; // This one requires a fix in SPIRV-val.
}

But OpRuntimeArray has a few restrictions, one of them is the storage class must be either Uniform, StorageBuffer or UniformConstant. So IIRC, we wouldn't be able to translate this as it would require the Workgroup storage class.

Same for a local variable:

[numthreads(1, 1, 1)]
void main(uint3 threadId : SV_DispatchThreadID)
{
  int array[0];
}

So we might have to emit an error saying this specific case is not supported in SPIR-V.

Keenuts commented 3 months ago

Turns out, it seems groupshared int PoorlySizedArray[0]; should be illegal in HLSL. @tex3d

Could you confirm/deny those are legal in HLSL? My understanding was that if the array size is zero, then its considered as "an array which size is defined at runtime", but seems like it's a bit more than that:

A: illegal, local arrays cannot have a size=0

[numthreads(1, 1, 1)]
void main(uint3 threadId : SV_DispatchThreadID)
{
  int array[0];
}

B: legal, the array size is only known at runtime

cbuffer buffer {
    int array[0]; // This one requires a fix in SPIRV-val.
}

C: legal: the array size is only known at runtime

Texture2D<float4> tex1[0] : register(t0);

D: illegal?

groupshared int PoorlySizedArray[0];
Keenuts commented 3 months ago

@tex3d friendly ping

Keenuts commented 3 months ago

@tex3d friendly ping

Keenuts commented 2 months ago

@tex3d friendly ping

Keenuts commented 1 month ago

@tex3d friendly ping

damyanp commented 1 week ago

We're planning to clean up the language spec for this here: https://github.com/microsoft/hlsl-specs/issues/141

tex3d commented 1 week ago

Apologies for not addressing this before.

I don't think we should be supporting zero-length arrays at all. I think the way DXC supports this is an accident from failing to check and emit an error for this case.

We don't actually support runtime-sized arrays for groupshared memory or constant buffer arrays using a [0] array size, in spite of the fact that DXC will not emit an error for these cases today.

We support unbounded resource arrays, but the syntax DXC supports for that does not include any dimension value (like RWBuffer buffers[]).

Note that FXC supports [0] and maps it to an unbounded resource array, but DXC doesn't interpret this in the same way. For DXC, this results in a zero-length resource range instead (which seems like it should be invalid).

We could choose to emit an error when using [0] for resources for consistency with disallowing [0] sized arrays in all other cases, with the known issue that some code that compiled on FXC won't compile on DXC. This seems like the best option however, since that code doesn't work correctly on DXC today anyway. It's better to emit an error than quietly do something unintended.