April 28, 2022 4:22 PM, "Zebediah Figura" <zfigura@codeweavers.com (mailto:zfigura@codeweavers.com)> wrote: On 4/28/22 14:45, Francisco Casas wrote: diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 905dbfc5..e7fe74d8 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1606,7 +1606,27 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t type = basic_type; for (i = 0; i < v->arrays.count; ++i) + { + if (v->arrays.sizes[i] == HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT) + { + unsigned int size = initializer_size(&v->initializer); + unsigned int elem_components = hlsl_type_component_count(type); + + assert(v->initializer.args_count); + + v->arrays.sizes[i] = (size + elem_components - 1)/elem_components; + + if (size % elem_components != 0) + { + hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, + "Cannot initialize implicit array with %u components, expected a multiple of %u.", + size, elem_components); + free_parse_initializer(&v->initializer); + v->initializer.args_count = 0; + } This doesn't seem like it'll do the right thing for implicit sizes on an inner array, especially considering that the right thing is probably to fail compilation.
It also won't do the right thing for initializers without braces (viz. also fail compilation).These cases are checked in the parse rules introduced in this patch.
Oh, I see, I wasn't actually correctly reading the parser rule. That makes sense.
On the other hand, handling IMPLICIT inside of the loop, without any checks, was one of the things that made me think "we're not handling inner arrays correctly", so arguably something deserves changing here :-) Well, the structure of the parsing rule ensures that only the most external array could have IMPLICIT side. This is related to the assert(i == v->arrays.count - 1); suggested by Giovanni. I don't see any handling for braceless initializers in this patch, though; am I missing something? The error is added to the "variable_def:" rule. But then again, maybe it is not so clear that the parse rule ensures that only the most external array can have IMPLICIT size. I could add the same assertion here too.
By the way, I am not sure if you changed your stance on checking the implicit size arrays at the parse level. I would prefer to keep it there... if I find a way of also handling these unbounded resource arrays nicely. I think we need tests for all of these corner cases, and also a test for missing initializers. Okay, adding them. + } type = hlsl_new_array_type(ctx, type, v->arrays.sizes[i]); + } vkd3d_free(v->arrays.sizes); if (type->type != HLSL_CLASS_MATRIX) @@ -2464,6 +2484,7 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl %token <name> TYPE_IDENTIFIER %type <arrays> arrays +%type <arrays> implicit_arrays %type <assign_op> assign_op @@ -3108,7 +3129,7 @@ variables_def: } variable_decl: - any_identifier arrays colon_attribute + any_identifier implicit_arrays colon_attribute { $$ = hlsl_alloc(ctx, sizeof(*$$)); $$->loc = @1; @@ -3137,6 +3158,15 @@ state_block: variable_def: variable_decl + { + if ($$->arrays.sizes && $$->arrays.sizes[$$->arrays.count - 1] == HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT) + { + hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_MISSING_INITIALIZER, + "Implicit array requires initializer."); + free_parse_variable_def($$); + YYABORT; + } + } This won't work for unbounded resource arrays, which can be declared with an empty pair of brackets (and no initializer).I see, I didn't knew about those. It also aborts compilation somewhat unnecessarily. AFAIK (except for unbounded resource arrays) the native compiler doesn't allow implicit size arrays without initializer, so aborting seemed logical.
Failing compilation is fine, but in general I think we want to avoid aborting if we can help it. We should only abort if we really can't continue parsing, e.g. if we encounter a syntax error. That way, if there are multiple errors, the (HLSL) programmer can deal with them all at once. (As a side note, perhaps we should use zero instead of UINT_MAX. Unbounded resources in shader model 5.1 are encoded as zero in the reflection data, whereas declaring a resource array as e.g. "Texture2D t[0xffffffff]" yields 0xffffffff instead, although the shader bytecode is identical.)
As a special extra, this code is apparently valid, and I think deserves to be a test case:
struct apple { Texture2D t[]; };Hmm, this is interesting. Maybe it is intended for input semantics? I will investigate.
Not for input semantics, but rather for bound resources. Shader model 5.0 allows declaring arrays of textures, and shader model 5.1 (and Direct3D 12) allows declaring "unbounded" arrays, as e.g. "Texture2D t[]" or "Texture2D t[0]".
Normally textures aren't declared as part of a struct, but I was curious to see if it was legal, and it turns out it is. (Although the reflection type information that's generated isn't quite correct.) Hmm, I will see where I can add a FIXME for those cases for now then.