From f843a7babbee093caa9873f0cd7ac0ac44b7a95d Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Tue, 16 Aug 2022 12:33:51 -0400
Subject: [PATCH 01/11] vkd3d-shader/hlsl: Rename 'inner_type' to
 'element_type' in function name.

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 libs/vkd3d-shader/hlsl.c         | 6 +++---
 libs/vkd3d-shader/hlsl.h         | 2 +-
 libs/vkd3d-shader/hlsl_codegen.c | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index a47e3d2d1b..01709c8c68 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -370,7 +370,7 @@ static struct hlsl_type *get_type_from_deref(struct hlsl_ctx *ctx, const struct
 
     type = deref->var->data_type;
     for (i = 0; i < deref->path_len; ++i)
-        type = hlsl_get_inner_type_from_path_index(ctx, type, deref->path[i].node);
+        type = hlsl_get_element_type_from_path_index(ctx, type, deref->path[i].node);
     return type;
 }
 
@@ -423,7 +423,7 @@ static bool init_deref_from_component_index(struct hlsl_ctx *ctx, struct hlsl_bl
     return true;
 }
 
-struct hlsl_type *hlsl_get_inner_type_from_path_index(struct hlsl_ctx *ctx, const struct hlsl_type *type,
+struct hlsl_type *hlsl_get_element_type_from_path_index(struct hlsl_ctx *ctx, const struct hlsl_type *type,
         struct hlsl_ir_node *idx)
 {
     assert(idx);
@@ -963,7 +963,7 @@ struct hlsl_ir_load *hlsl_new_load_index(struct hlsl_ctx *ctx, const struct hlsl
 
     type = get_type_from_deref(ctx, deref);
     if (idx)
-        type = hlsl_get_inner_type_from_path_index(ctx, type, idx);
+        type = hlsl_get_element_type_from_path_index(ctx, type, idx);
 
     if (!(load = hlsl_alloc(ctx, sizeof(*load))))
         return NULL;
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h
index 7970665c31..96466ee1d6 100644
--- a/libs/vkd3d-shader/hlsl.h
+++ b/libs/vkd3d-shader/hlsl.h
@@ -735,7 +735,7 @@ struct hlsl_ir_function_decl *hlsl_get_func_decl(struct hlsl_ctx *ctx, const cha
 struct hlsl_type *hlsl_get_type(struct hlsl_scope *scope, const char *name, bool recursive);
 struct hlsl_ir_var *hlsl_get_var(struct hlsl_scope *scope, const char *name);
 
-struct hlsl_type *hlsl_get_inner_type_from_path_index(struct hlsl_ctx *ctx, const struct hlsl_type *type,
+struct hlsl_type *hlsl_get_element_type_from_path_index(struct hlsl_ctx *ctx, const struct hlsl_type *type,
         struct hlsl_ir_node *idx);
 
 struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *basic_type, unsigned int array_size);
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c
index 36a417e556..cae663cf15 100644
--- a/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d-shader/hlsl_codegen.c
@@ -116,7 +116,7 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st
 
         list_move_tail(&block->instrs, &idx_block.instrs);
 
-        type = hlsl_get_inner_type_from_path_index(ctx, type, deref->path[i].node);
+        type = hlsl_get_element_type_from_path_index(ctx, type, deref->path[i].node);
     }
 
     return offset;
-- 
GitLab


From f3432966da1ba513db048078b0f7e2d780d8c91f Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Wed, 3 Aug 2022 14:55:14 -0400
Subject: [PATCH 02/11] vkd3d-shader/hlsl: Emit a fixme on complex resource
 load object derefs.

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 libs/vkd3d-shader/hlsl_sm4.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c
index cdd73e571e..fab2abe2c4 100644
--- a/libs/vkd3d-shader/hlsl_sm4.c
+++ b/libs/vkd3d-shader/hlsl_sm4.c
@@ -2082,11 +2082,23 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx,
     const struct hlsl_ir_node *texel_offset = load->texel_offset.node;
     const struct hlsl_ir_node *coords = load->coords.node;
 
+    if (resource_type->type != HLSL_CLASS_OBJECT)
+    {
+        assert(resource_type->type == HLSL_CLASS_ARRAY || resource_type->type == HLSL_CLASS_STRUCT);
+        hlsl_fixme(ctx, &load->node.loc, "Resource being a component of another variable.");
+        return;
+    }
+
     if (load->sampler.var)
     {
         const struct hlsl_type *sampler_type = load->sampler.var->data_type;
 
-        assert(sampler_type->type == HLSL_CLASS_OBJECT);
+        if (sampler_type->type != HLSL_CLASS_OBJECT)
+        {
+            assert(sampler_type->type == HLSL_CLASS_ARRAY || sampler_type->type == HLSL_CLASS_STRUCT);
+            hlsl_fixme(ctx, &load->node.loc, "Sampler being a component of another variable.");
+            return;
+        }
         assert(sampler_type->base_type == HLSL_TYPE_SAMPLER);
         assert(sampler_type->sampler_dim == HLSL_SAMPLER_DIM_GENERIC);
 
-- 
GitLab


From e9829fdc6524e455f85893445ad8a2d703f02a2e Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Mon, 8 Aug 2022 12:21:55 -0400
Subject: [PATCH 03/11] tests: Test object references.

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 Makefile.am                         |   1 +
 tests/object-references.shader_test | 120 ++++++++++++++++++++++++++++
 2 files changed, 121 insertions(+)
 create mode 100644 tests/object-references.shader_test

diff --git a/Makefile.am b/Makefile.am
index 60db7794b4..962036ff49 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -115,6 +115,7 @@ vkd3d_shader_tests = \
 	tests/matrix-semantics.shader_test \
 	tests/multiple-rt.shader_test \
 	tests/nointerpolation.shader_test \
+	tests/object-references.shader_test
 	tests/pow.shader_test \
 	tests/preproc-if.shader_test \
 	tests/preproc-ifdef.shader_test \
diff --git a/tests/object-references.shader_test b/tests/object-references.shader_test
new file mode 100644
index 0000000000..c3952e03d3
--- /dev/null
+++ b/tests/object-references.shader_test
@@ -0,0 +1,120 @@
+[require]
+shader model >= 4.0
+
+[texture 0]
+size (2, 2)
+0.1 0.2 0.3 0.4     0.5 0.7 0.6 0.8
+0.6 0.5 0.2 0.1     0.8 0.0 0.7 1.0
+
+[pixel shader]
+Texture2D t;
+
+struct foo {
+    int3 a;
+    Texture2D b;
+};
+
+float4 main(float4 pos : sv_position) : sv_target
+{
+    struct foo q;
+
+    q.a = int3(pos.xy, 0);
+    q.b = t;
+    return q.b.Load(q.a);
+}
+
+[test]
+draw quad
+probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4)
+probe (1, 0) rgba (0.5, 0.7, 0.6, 0.8)
+probe (0, 1) rgba (0.6, 0.5, 0.2, 0.1)
+probe (1, 1) rgba (0.8, 0.0, 0.7, 1.0)
+
+
+[texture 0]
+size (1, 1)
+1.0 1.0 1.0 1.0
+
+[texture 1]
+size (1, 1)
+2.0 2.0 2.0 1.0
+
+[texture 2]
+size (1, 1)
+3.0 3.0 3.0 1.0
+
+[pixel shader]
+Texture2D tex[3];
+
+struct foo {
+    float4 p;
+    Texture2D t;
+};
+
+float4 main() : sv_target
+{
+    struct foo s[3];
+
+    s[0].t = tex[0];
+    s[1].t = tex[1];
+    s[2].t = tex[2];
+    return 100 * s[2].t.Load(0) + 10 * s[0].t.Load(0) + s[1].t.Load(0);
+}
+
+[test]
+todo draw quad
+todo probe all rgba (312, 312, 312, 111)
+
+
+[pixel shader]
+Texture2D tex1;
+Texture2D tex2;
+Texture2D tex3;
+
+float4 main() : sv_target
+{
+    Texture2D t[3][2];
+
+    t[0][0] = tex1; // Note: Only invalid in shader model 5.1, array ref. cannot be used as l-value.
+    t[0][1] = tex2;
+    t[1][0] = tex3;
+    t[1][1] = tex1;
+    t[2][0] = tex2;
+    t[2][1] = tex3;
+    return 1000 * t[2][0].Load(0) + 100 * t[1][1].Load(0) + 10 * t[2][1].Load(0) + t[0][1].Load(0);
+}
+
+[test]
+draw quad
+probe all rgba (2132, 2132, 2132, 1111)
+
+
+[pixel shader fail todo]
+Texture2D tex[3];
+uniform int n;
+
+struct foo {
+    float4 p;
+    Texture2D t;
+};
+
+float4 main() : sv_target
+{
+    struct foo s[3];
+
+    s[0].t = tex[0];
+    s[1].t = tex[1];
+    s[2].t = tex[2];
+    return s[n].t.Load(0);
+}
+
+
+[pixel shader fail todo]
+// Note: Only valid in shader model 5.1
+Texture2D tex[3];
+uniform int n;
+
+float4 main() : sv_target
+{
+    return tex[n].Load(0);
+}
-- 
GitLab


From 732f1737f4ce680fab2433ae3b595df2730a273d Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Fri, 22 Jul 2022 12:42:17 -0400
Subject: [PATCH 04/11] vkd3d-shader/hlsl: Set component count for objects to
 1.

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 libs/vkd3d-shader/hlsl.c                   | 41 +++++++++++++---------
 tests/hlsl-initializer-objects.shader_test |  4 +--
 2 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index 01709c8c68..e5b2e8e43d 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -548,25 +548,32 @@ struct hlsl_ir_function_decl *hlsl_get_func_decl(struct hlsl_ctx *ctx, const cha
 
 unsigned int hlsl_type_component_count(const struct hlsl_type *type)
 {
-    unsigned int count = 0, i;
-
-    if (type->type <= HLSL_CLASS_LAST_NUMERIC)
-    {
-        return type->dimx * type->dimy;
-    }
-    if (type->type == HLSL_CLASS_ARRAY)
-    {
-        return hlsl_type_component_count(type->e.array.type) * type->e.array.elements_count;
-    }
-    if (type->type != HLSL_CLASS_STRUCT)
+    switch (type->type)
     {
-        ERR("Unexpected data type %#x.\n", type->type);
-        return 0;
-    }
+        case HLSL_CLASS_SCALAR:
+        case HLSL_CLASS_VECTOR:
+        case HLSL_CLASS_MATRIX:
+            return type->dimx * type->dimy;
+
+        case HLSL_CLASS_STRUCT:
+        {
+            unsigned int count = 0, i;
+
+            for (i = 0; i < type->e.record.field_count; ++i)
+                count += hlsl_type_component_count(type->e.record.fields[i].type);
+            return count;
+        }
+
+        case HLSL_CLASS_ARRAY:
+            return hlsl_type_component_count(type->e.array.type) * type->e.array.elements_count;
 
-    for (i = 0; i < type->e.record.field_count; ++i)
-        count += hlsl_type_component_count(type->e.record.fields[i].type);
-    return count;
+        case HLSL_CLASS_OBJECT:
+            return 1;
+
+        default:
+            assert(0);
+            return 0;
+    }
 }
 
 bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2)
diff --git a/tests/hlsl-initializer-objects.shader_test b/tests/hlsl-initializer-objects.shader_test
index 2306d07f27..70f060c22f 100644
--- a/tests/hlsl-initializer-objects.shader_test
+++ b/tests/hlsl-initializer-objects.shader_test
@@ -71,7 +71,7 @@ float4 main() : sv_target
 }
 
 
-[pixel shader fail todo]
+[pixel shader fail]
 Texture2D tex;
 
 struct foo
@@ -90,7 +90,7 @@ float4 main() : sv_target
 }
 
 
-[pixel shader fail todo]
+[pixel shader fail]
 Texture2D tex;
 
 struct foo
-- 
GitLab


From a8b77b85ca97cec22eac6ce7eede78a8cfe3b783 Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Fri, 22 Jul 2022 15:28:19 -0400
Subject: [PATCH 05/11] vkd3d-shader/hlsl: Skip implicit conversion if types
 are equal.

Otherwise we get false in implicit_compatible_data_types() when passing
types that are equal but not convertible according to
convertible_data_type(); e.g. getting:

"Can't implicitly convert from Texture2D<float4> to Texture2D<float4>."

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 libs/vkd3d-shader/hlsl.y                   | 3 +++
 tests/hlsl-initializer-objects.shader_test | 4 ++--
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y
index 7df7afb940..1e488afaae 100644
--- a/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d-shader/hlsl.y
@@ -370,6 +370,9 @@ static struct hlsl_ir_node *add_implicit_conversion(struct hlsl_ctx *ctx, struct
 {
     struct hlsl_type *src_type = node->data_type;
 
+    if (hlsl_types_are_equal(src_type, dst_type))
+        return node;
+
     if (!implicit_compatible_data_types(src_type, dst_type))
     {
         struct vkd3d_string_buffer *src_string, *dst_string;
diff --git a/tests/hlsl-initializer-objects.shader_test b/tests/hlsl-initializer-objects.shader_test
index 70f060c22f..dcb6002910 100644
--- a/tests/hlsl-initializer-objects.shader_test
+++ b/tests/hlsl-initializer-objects.shader_test
@@ -25,8 +25,8 @@ float4 main() : sv_target
 }
 
 [test]
-todo draw quad
-todo probe all rgba (0.2, 0.2, 0.2, 0.1)
+draw quad
+probe all rgba (0.2, 0.2, 0.2, 0.1)
 
 
 [pixel shader]
-- 
GitLab


From 10bd0c48f87cbf912740e3a7e657fb22541e572b Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Tue, 2 Aug 2022 11:11:15 -0400
Subject: [PATCH 06/11] vkd3d-shader/hlsl: Print halfs in dump_ir_constant().

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 libs/vkd3d-shader/hlsl.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index e5b2e8e43d..b27bdda319 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -1545,6 +1545,7 @@ static void dump_ir_constant(struct vkd3d_string_buffer *buffer, const struct hl
                 break;
 
             case HLSL_TYPE_FLOAT:
+            case HLSL_TYPE_HALF:
                 vkd3d_string_buffer_printf(buffer, "%.8e ", value->f);
                 break;
 
-- 
GitLab


From b5b08bd8a00c20ffdbbedcac4d69abc1b1df9c4b Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Wed, 20 Jul 2022 15:37:07 -0400
Subject: [PATCH 07/11] vkd3d-shader/hlsl: Replace register offsets with index
 paths in copy propagation.

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 libs/vkd3d-shader/hlsl.c         |   6 +-
 libs/vkd3d-shader/hlsl.h         |   3 +
 libs/vkd3d-shader/hlsl_codegen.c | 178 ++++++++++++++++++++++---------
 3 files changed, 135 insertions(+), 52 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index b27bdda319..b3c02e18e5 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -770,7 +770,7 @@ static bool type_is_single_reg(const struct hlsl_type *type)
     return type->type == HLSL_CLASS_SCALAR || type->type == HLSL_CLASS_VECTOR;
 }
 
-static bool copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_deref *other)
+bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_deref *other)
 {
     unsigned int i;
 
@@ -1036,8 +1036,8 @@ struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx *ctx, struc
         return NULL;
     init_node(&load->node, HLSL_IR_RESOURCE_LOAD, data_type, *loc);
     load->load_type = type;
-    copy_deref(ctx, &load->resource, resource);
-    copy_deref(ctx, &load->sampler, sampler);
+    hlsl_copy_deref(ctx, &load->resource, resource);
+    hlsl_copy_deref(ctx, &load->sampler, sampler);
     hlsl_src_from_node(&load->coords, coords);
     hlsl_src_from_node(&load->texel_offset, texel_offset);
     return load;
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h
index 96466ee1d6..d63fef97fb 100644
--- a/libs/vkd3d-shader/hlsl.h
+++ b/libs/vkd3d-shader/hlsl.h
@@ -721,6 +721,7 @@ void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl
 int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func,
         enum vkd3d_shader_target_type target_type, struct vkd3d_shader_code *out);
 
+bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_deref *other);
 void hlsl_cleanup_deref(struct hlsl_deref *deref);
 
 void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new);
@@ -821,6 +822,8 @@ unsigned int hlsl_combine_writemasks(unsigned int first, unsigned int second);
 unsigned int hlsl_map_swizzle(unsigned int swizzle, unsigned int writemask);
 unsigned int hlsl_swizzle_from_writemask(unsigned int writemask);
 
+bool hlsl_component_index_range_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref,
+        unsigned int *start, unsigned int *count);
 bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, unsigned int *offset);
 unsigned int hlsl_offset_from_deref_safe(struct hlsl_ctx *ctx, const struct hlsl_deref *deref);
 struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref);
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c
index cae663cf15..9e234ca301 100644
--- a/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d-shader/hlsl_codegen.c
@@ -541,7 +541,7 @@ static void copy_propagation_var_def_destroy(struct rb_entry *entry, void *conte
 }
 
 static struct copy_propagation_value *copy_propagation_get_value(const struct copy_propagation_state *state,
-        const struct hlsl_ir_var *var, unsigned component)
+        const struct hlsl_ir_var *var, unsigned int component)
 {
     for (; state; state = state->parent)
     {
@@ -549,9 +549,11 @@ static struct copy_propagation_value *copy_propagation_get_value(const struct co
         if (entry)
         {
             struct copy_propagation_var_def *var_def = RB_ENTRY_VALUE(entry, struct copy_propagation_var_def, entry);
-            enum copy_propagation_value_state state = var_def->values[component].state;
+            unsigned int component_count = hlsl_type_component_count(var->data_type);
+            enum copy_propagation_value_state state;
 
-            assert(component < var_def->var->data_type->reg_size);
+            assert(component < component_count);
+            state = var_def->values[component].state;
 
             switch (state)
             {
@@ -573,12 +575,13 @@ static struct copy_propagation_var_def *copy_propagation_create_var_def(struct h
 {
     struct rb_entry *entry = rb_get(&state->var_defs, var);
     struct copy_propagation_var_def *var_def;
+    unsigned int component_count = hlsl_type_component_count(var->data_type);
     int res;
 
     if (entry)
         return RB_ENTRY_VALUE(entry, struct copy_propagation_var_def, entry);
 
-    if (!(var_def = hlsl_alloc(ctx, offsetof(struct copy_propagation_var_def, values[var->data_type->reg_size]))))
+    if (!(var_def = hlsl_alloc(ctx, offsetof(struct copy_propagation_var_def, values[component_count]))))
         return NULL;
 
     var_def->var = var;
@@ -590,31 +593,32 @@ static struct copy_propagation_var_def *copy_propagation_create_var_def(struct h
 }
 
 static void copy_propagation_invalidate_variable(struct copy_propagation_var_def *var_def,
-        unsigned offset, unsigned char writemask)
+        unsigned int comp, unsigned char writemask)
 {
     unsigned i;
 
-    TRACE("Invalidate variable %s[%u]%s.\n", var_def->var->name, offset, debug_hlsl_writemask(writemask));
+    TRACE("Invalidate variable %s[%u]%s.\n", var_def->var->name, comp, debug_hlsl_writemask(writemask));
 
     for (i = 0; i < 4; ++i)
     {
         if (writemask & (1u << i))
-            var_def->values[offset + i].state = VALUE_STATE_DYNAMICALLY_WRITTEN;
+            var_def->values[comp + i].state = VALUE_STATE_DYNAMICALLY_WRITTEN;
     }
 }
 
 static void copy_propagation_invalidate_whole_variable(struct copy_propagation_var_def *var_def)
 {
+    unsigned int component_count = hlsl_type_component_count(var_def->var->data_type);
     unsigned i;
 
     TRACE("Invalidate variable %s.\n", var_def->var->name);
 
-    for (i = 0; i < var_def->var->data_type->reg_size; ++i)
+    for (i = 0; i < component_count; ++i)
         var_def->values[i].state = VALUE_STATE_DYNAMICALLY_WRITTEN;
 }
 
-static void copy_propagation_set_value(struct copy_propagation_var_def *var_def, unsigned int offset,
-        unsigned char writemask, struct hlsl_ir_node *node)
+static void copy_propagation_set_value(struct copy_propagation_var_def *var_def, unsigned int comp,
+        unsigned char writemask, struct hlsl_ir_node *instr)
 {
     unsigned int i, j = 0;
 
@@ -623,59 +627,56 @@ static void copy_propagation_set_value(struct copy_propagation_var_def *var_def,
         if (writemask & (1u << i))
         {
             TRACE("Variable %s[%u] is written by instruction %p%s.\n",
-                    var_def->var->name, offset + i, node, debug_hlsl_writemask(1u << i));
-            var_def->values[offset + i].state = VALUE_STATE_STATICALLY_WRITTEN;
-            var_def->values[offset + i].node = node;
-            var_def->values[offset + i].component = j++;
+                    var_def->var->name, comp + i, instr, debug_hlsl_writemask(1u << i));
+            var_def->values[comp + i].state = VALUE_STATE_STATICALLY_WRITTEN;
+            var_def->values[comp + i].node = instr;
+            var_def->values[comp + i].component = j++;
         }
     }
 }
 
 static struct hlsl_ir_node *copy_propagation_compute_replacement(struct hlsl_ctx *ctx,
         const struct copy_propagation_state *state, const struct hlsl_deref *deref,
-        unsigned int count, unsigned int *swizzle)
+        unsigned int *swizzle)
 {
     const struct hlsl_ir_var *var = deref->var;
-    struct hlsl_ir_node *node = NULL;
-    unsigned int offset, i;
+    struct hlsl_ir_node *instr = NULL;
+    unsigned int start, count, i;
 
-    if (!hlsl_offset_from_deref(ctx, deref, &offset))
+    if (!hlsl_component_index_range_from_deref(ctx, deref, &start, &count))
         return NULL;
 
-    if (var->data_type->type != HLSL_CLASS_OBJECT)
-        assert(offset + count <= var->data_type->reg_size);
-
     *swizzle = 0;
 
     for (i = 0; i < count; ++i)
     {
-        struct copy_propagation_value *value = copy_propagation_get_value(state, var, offset + i);
+        struct copy_propagation_value *value = copy_propagation_get_value(state, var, start + i);
 
         if (!value)
             return NULL;
 
-        if (!node)
+        if (!instr)
         {
-            node = value->node;
+            instr = value->node;
         }
-        else if (node != value->node)
+        else if (instr != value->node)
         {
-            TRACE("No single source for propagating load from %s[%u-%u].\n", var->name, offset, offset + count);
+            TRACE("No single source for propagating load from %s[%u-%u].\n", var->name, start, start + count);
             return NULL;
         }
         *swizzle |= value->component << i * 2;
     }
 
     TRACE("Load from %s[%u-%u] propagated as instruction %p%s.\n",
-            var->name, offset, offset + count, node, debug_hlsl_swizzle(*swizzle, count));
-    return node;
+            var->name, start, start + count, instr, debug_hlsl_swizzle(*swizzle, count));
+    return instr;
 }
 
 static bool copy_propagation_transform_load(struct hlsl_ctx *ctx,
         struct hlsl_ir_load *load, struct copy_propagation_state *state)
 {
-    struct hlsl_ir_node *node = &load->node, *new_node;
-    struct hlsl_type *type = node->data_type;
+    struct hlsl_ir_node *instr = &load->node, *new_instr;
+    struct hlsl_type *type = instr->data_type;
     struct hlsl_ir_swizzle *swizzle_node;
     unsigned int dimx = 0;
     unsigned int swizzle;
@@ -699,17 +700,17 @@ static bool copy_propagation_transform_load(struct hlsl_ctx *ctx,
             return false;
     }
 
-    if (!(new_node = copy_propagation_compute_replacement(ctx, state, &load->src, dimx, &swizzle)))
+    if (!(new_instr = copy_propagation_compute_replacement(ctx, state, &load->src, &swizzle)))
         return false;
 
     if (type->type != HLSL_CLASS_OBJECT)
     {
-        if (!(swizzle_node = hlsl_new_swizzle(ctx, swizzle, dimx, new_node, &node->loc)))
+        if (!(swizzle_node = hlsl_new_swizzle(ctx, swizzle, dimx, new_instr, &instr->loc)))
             return false;
-        list_add_before(&node->entry, &swizzle_node->node.entry);
-        new_node = &swizzle_node->node;
+        list_add_before(&instr->entry, &swizzle_node->node.entry);
+        new_instr = &swizzle_node->node;
     }
-    hlsl_replace_node(node, new_node);
+    hlsl_replace_node(instr, new_instr);
     return true;
 }
 
@@ -717,17 +718,18 @@ static bool copy_propagation_transform_object_load(struct hlsl_ctx *ctx,
         struct hlsl_deref *deref, struct copy_propagation_state *state)
 {
     struct hlsl_ir_load *load;
-    struct hlsl_ir_node *node;
+    struct hlsl_ir_node *instr;
     unsigned int swizzle;
 
-    if (!(node = copy_propagation_compute_replacement(ctx, state, deref, 1, &swizzle)))
+    if (!(instr = copy_propagation_compute_replacement(ctx, state, deref, &swizzle)))
         return false;
 
     /* Only HLSL_IR_LOAD can produce an object. */
-    load = hlsl_ir_load(node);
-    deref->var = load->src.var;
-    hlsl_src_remove(&deref->offset);
-    hlsl_src_from_node(&deref->offset, load->src.offset.node);
+    load = hlsl_ir_load(instr);
+
+    hlsl_cleanup_deref(deref);
+    hlsl_copy_deref(ctx, deref, &load->src);
+
     return true;
 }
 
@@ -748,18 +750,18 @@ static void copy_propagation_record_store(struct hlsl_ctx *ctx, struct hlsl_ir_s
     struct copy_propagation_var_def *var_def;
     struct hlsl_deref *lhs = &store->lhs;
     struct hlsl_ir_var *var = lhs->var;
-    unsigned int offset;
+    unsigned int start, count;
 
     if (!(var_def = copy_propagation_create_var_def(ctx, state, var)))
         return;
 
-    if (hlsl_offset_from_deref(ctx, lhs, &offset))
+    if (hlsl_component_index_range_from_deref(ctx, lhs, &start, &count))
     {
         unsigned int writemask = store->writemask;
 
         if (store->rhs.node->data_type->type == HLSL_CLASS_OBJECT)
             writemask = VKD3DSP_WRITEMASK_0;
-        copy_propagation_set_value(var_def, offset, writemask, store->rhs.node);
+        copy_propagation_set_value(var_def, start, writemask, store->rhs.node);
     }
     else
     {
@@ -794,13 +796,13 @@ static void copy_propagation_invalidate_from_block(struct hlsl_ctx *ctx, struct
                 struct copy_propagation_var_def *var_def;
                 struct hlsl_deref *lhs = &store->lhs;
                 struct hlsl_ir_var *var = lhs->var;
-                unsigned int offset;
+                unsigned int start, count;
 
                 if (!(var_def = copy_propagation_create_var_def(ctx, state, var)))
                     continue;
 
-                if (hlsl_offset_from_deref(ctx, lhs, &offset))
-                    copy_propagation_invalidate_variable(var_def, offset, store->writemask);
+                if (hlsl_component_index_range_from_deref(ctx, lhs, &start, &count))
+                    copy_propagation_invalidate_variable(var_def, start, store->writemask);
                 else
                     copy_propagation_invalidate_whole_variable(var_def);
 
@@ -1996,6 +1998,82 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_base_type type)
     }
 }
 
+bool hlsl_component_index_range_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref,
+        unsigned int *start, unsigned int *count)
+{
+    struct hlsl_type *type = deref->var->data_type;
+    unsigned int i, k;
+
+    *start = 0;
+    *count = 0;
+
+    for (i = 0; i < deref->path_len; ++i)
+    {
+        struct hlsl_ir_node *path_node = deref->path[i].node;
+        unsigned int idx = 0;
+
+        assert(path_node);
+        if (path_node->type != HLSL_IR_CONSTANT)
+            return false;
+
+        /* We should always have generated a cast to UINT. */
+        assert(path_node->data_type->type == HLSL_CLASS_SCALAR
+                && path_node->data_type->base_type == HLSL_TYPE_UINT);
+
+        idx = hlsl_ir_constant(path_node)->value[0].u;
+
+        switch (type->type)
+        {
+            case HLSL_CLASS_VECTOR:
+                if (idx >= type->dimx)
+                {
+                    hlsl_error(ctx, &path_node->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS,
+                            "Vector index is out of bounds. %u/%u", idx, type->dimx);
+                    return false;
+                }
+                *start += idx;
+                break;
+
+            case HLSL_CLASS_MATRIX:
+                if (idx >= hlsl_type_major_size(type))
+                {
+                    hlsl_error(ctx, &path_node->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS,
+                            "Matrix index is out of bounds. %u/%u", idx, hlsl_type_major_size(type));
+                    return false;
+                }
+                if (hlsl_type_is_row_major(type))
+                    *start += idx * type->dimx;
+                else
+                    *start += idx * type->dimy;
+                break;
+
+            case HLSL_CLASS_ARRAY:
+                if (idx >= type->e.array.elements_count)
+                {
+                    hlsl_error(ctx, &path_node->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS,
+                            "Array index is out of bounds. %u/%u", idx, type->e.array.elements_count);
+                    return false;
+                }
+                *start += idx * hlsl_type_component_count(type->e.array.type);
+                break;
+
+            case HLSL_CLASS_STRUCT:
+                for (k = 0; k < idx; ++k)
+                    *start += hlsl_type_component_count(type->e.record.fields[k].type);
+                break;
+
+            default:
+                assert(0);
+                break;
+        }
+
+        type = hlsl_get_element_type_from_path_index(ctx, type, path_node);
+    }
+
+    *count = hlsl_type_component_count(type);
+    return true;
+}
+
 bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, unsigned int *offset)
 {
     struct hlsl_ir_node *offset_node = deref->offset.node;
@@ -2105,8 +2183,6 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
     while (progress);
     transform_ir(ctx, split_matrix_copies, body, NULL);
 
-    transform_ir(ctx, transform_deref_paths_into_offsets, body, NULL); /* TODO: move forward, remove when no longer needed */
-
     transform_ir(ctx, lower_narrowing_casts, body, NULL);
     transform_ir(ctx, lower_casts_to_bool, body, NULL);
     do
@@ -2121,6 +2197,10 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
     if (ctx->profile->major_version < 4)
         transform_ir(ctx, lower_division, body, NULL);
 
+    /* TODO: move forward, remove when no longer needed */
+    transform_ir(ctx, transform_deref_paths_into_offsets, body, NULL);
+    while (transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL));
+
     do
         compute_liveness(ctx, entry_func);
     while (transform_ir(ctx, dce, body, NULL));
-- 
GitLab


From 1bba18aa75863ba862b1ff90fd31ee74fd6ec7ef Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Wed, 20 Jul 2022 17:42:13 -0400
Subject: [PATCH 08/11] vkd3d-shader/hlsl: Invalidate components more precisely
 in copy propagation.

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 libs/vkd3d-shader/hlsl.c         | 17 +++++++++
 libs/vkd3d-shader/hlsl.h         |  1 +
 libs/vkd3d-shader/hlsl_codegen.c | 63 ++++++++++++++++++++++++++------
 3 files changed, 69 insertions(+), 12 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index b3c02e18e5..38df7e8a4d 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -140,6 +140,23 @@ unsigned int hlsl_type_major_size(const struct hlsl_type *type)
         return type->dimx;
 }
 
+unsigned int hlsl_type_element_count(const struct hlsl_type *type)
+{
+    switch (type->type)
+    {
+        case HLSL_CLASS_VECTOR:
+            return type->dimx;
+        case HLSL_CLASS_MATRIX:
+            return hlsl_type_major_size(type);
+        case HLSL_CLASS_ARRAY:
+            return type->e.array.elements_count;
+        case HLSL_CLASS_STRUCT:
+            return type->e.record.field_count;
+        default:
+            return 0;
+    }
+}
+
 static unsigned int get_array_size(const struct hlsl_type *type)
 {
     if (type->type == HLSL_CLASS_ARRAY)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h
index d63fef97fb..54902c3743 100644
--- a/libs/vkd3d-shader/hlsl.h
+++ b/libs/vkd3d-shader/hlsl.h
@@ -814,6 +814,7 @@ struct hlsl_type *hlsl_type_get_component_type(struct hlsl_ctx *ctx, struct hlsl
 bool hlsl_type_is_row_major(const struct hlsl_type *type);
 unsigned int hlsl_type_minor_size(const struct hlsl_type *type);
 unsigned int hlsl_type_major_size(const struct hlsl_type *type);
+unsigned int hlsl_type_element_count(const struct hlsl_type *type);
 unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset);
 bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2);
 
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c
index 9e234ca301..7f76fce19a 100644
--- a/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d-shader/hlsl_codegen.c
@@ -606,15 +606,58 @@ static void copy_propagation_invalidate_variable(struct copy_propagation_var_def
     }
 }
 
-static void copy_propagation_invalidate_whole_variable(struct copy_propagation_var_def *var_def)
+static void copy_propagation_invalidate_variable_from_deref_recurse(struct hlsl_ctx *ctx,
+        struct copy_propagation_var_def *var_def, const struct hlsl_deref *deref,
+        struct hlsl_type *type, unsigned int depth, unsigned int comp_start, unsigned char writemask)
 {
-    unsigned int component_count = hlsl_type_component_count(var_def->var->data_type);
-    unsigned i;
+    unsigned int i, subtype_comp_count;
+    struct hlsl_ir_node *path_node;
+    struct hlsl_type *subtype;
 
-    TRACE("Invalidate variable %s.\n", var_def->var->name);
+    if (depth == deref->path_len)
+    {
+        copy_propagation_invalidate_variable(var_def, comp_start, writemask);
+        return;
+    }
 
-    for (i = 0; i < component_count; ++i)
-        var_def->values[i].state = VALUE_STATE_DYNAMICALLY_WRITTEN;
+    path_node = deref->path[depth].node;
+    subtype = hlsl_get_element_type_from_path_index(ctx, type, path_node);
+
+    if (type->type == HLSL_CLASS_STRUCT)
+    {
+        unsigned int idx = hlsl_ir_constant(path_node)->value[0].u;
+
+        for (i = 0; i < idx; ++i)
+            comp_start += hlsl_type_component_count(type->e.record.fields[i].type);
+
+        copy_propagation_invalidate_variable_from_deref_recurse(ctx, var_def, deref, subtype,
+                depth + 1, comp_start, writemask);
+    }
+    else
+    {
+        subtype_comp_count = hlsl_type_component_count(subtype);
+
+        if (path_node->type == HLSL_IR_CONSTANT)
+        {
+            copy_propagation_invalidate_variable_from_deref_recurse(ctx, var_def, deref, subtype,
+                    depth + 1, hlsl_ir_constant(path_node)->value[0].u * subtype_comp_count, writemask);
+        }
+        else
+        {
+            for (i = 0; i < hlsl_type_element_count(type); ++i)
+            {
+                copy_propagation_invalidate_variable_from_deref_recurse(ctx, var_def, deref, subtype,
+                        depth + 1, i * subtype_comp_count, writemask);
+            }
+        }
+    }
+}
+
+static void copy_propagation_invalidate_variable_from_deref(struct hlsl_ctx *ctx,
+        struct copy_propagation_var_def *var_def, const struct hlsl_deref *deref, unsigned char writemask)
+{
+    copy_propagation_invalidate_variable_from_deref_recurse(ctx, var_def, deref, deref->var->data_type,
+            0, 0, writemask);
 }
 
 static void copy_propagation_set_value(struct copy_propagation_var_def *var_def, unsigned int comp,
@@ -765,7 +808,7 @@ static void copy_propagation_record_store(struct hlsl_ctx *ctx, struct hlsl_ir_s
     }
     else
     {
-        copy_propagation_invalidate_whole_variable(var_def);
+        copy_propagation_invalidate_variable_from_deref(ctx, var_def, lhs, store->writemask);
     }
 }
 
@@ -796,15 +839,11 @@ static void copy_propagation_invalidate_from_block(struct hlsl_ctx *ctx, struct
                 struct copy_propagation_var_def *var_def;
                 struct hlsl_deref *lhs = &store->lhs;
                 struct hlsl_ir_var *var = lhs->var;
-                unsigned int start, count;
 
                 if (!(var_def = copy_propagation_create_var_def(ctx, state, var)))
                     continue;
 
-                if (hlsl_component_index_range_from_deref(ctx, lhs, &start, &count))
-                    copy_propagation_invalidate_variable(var_def, start, store->writemask);
-                else
-                    copy_propagation_invalidate_whole_variable(var_def);
+                copy_propagation_invalidate_variable_from_deref(ctx, var_def, lhs, store->writemask);
 
                 break;
             }
-- 
GitLab


From 6989266e76fc670a92b68e3fa064d16706cce070 Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Fri, 22 Jul 2022 11:40:24 -0400
Subject: [PATCH 09/11] vkd3d-shader/hlsl: Check for non-static object
 references.

It is responsibility of the shader's programmer to ensure that
object references can be solved statically.

Resource arrays for ps_5_1 and vs_5_1 are an exception which is not
properly handled yet. They probably deserve a different object type.

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 libs/vkd3d-shader/hlsl_codegen.c         | 47 ++++++++++++++++++++++++
 libs/vkd3d-shader/vkd3d_shader_private.h |  1 +
 tests/object-references.shader_test      |  4 +-
 3 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c
index 7f76fce19a..6c4a0eec62 100644
--- a/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d-shader/hlsl_codegen.c
@@ -967,6 +967,51 @@ static bool copy_propagation_execute(struct hlsl_ctx *ctx, struct hlsl_block *bl
     return progress;
 }
 
+static void note_non_static_deref_expressions(struct hlsl_ctx *ctx, const struct hlsl_deref *deref,
+        const char *usage)
+{
+    unsigned int i;
+
+    for (i = 0; i < deref->path_len; ++i)
+    {
+        struct hlsl_ir_node *path_node = deref->path[i].node;
+
+        assert(path_node);
+        if (path_node->type != HLSL_IR_CONSTANT)
+            hlsl_note(ctx, &path_node->loc, VKD3D_SHADER_LOG_ERROR,
+                    "Expression for %s within \"%s\" cannot be resolved statically.",
+                    usage, deref->var->name);
+    }
+}
+
+static bool validate_static_object_references(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr,
+        void *context)
+{
+    unsigned int start, count;
+
+    if (instr->type == HLSL_IR_RESOURCE_LOAD)
+    {
+        struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(instr);
+
+        if (!hlsl_component_index_range_from_deref(ctx, &load->resource, &start, &count))
+        {
+            hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF,
+                    "Loaded resource from \"%s\" must be determinable at compile time.",
+                    load->resource.var->name);
+            note_non_static_deref_expressions(ctx, &load->resource, "loaded resource");
+        }
+        if (load->sampler.var && !hlsl_component_index_range_from_deref(ctx, &load->sampler, &start, &count))
+        {
+            hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF,
+                    "Resource load sampler from \"%s\" must be determinable at compile time.",
+                    load->sampler.var->name);
+            note_non_static_deref_expressions(ctx, &load->sampler, "resource load sampler");
+        }
+    }
+
+    return false;
+}
+
 static bool is_vec1(const struct hlsl_type *type)
 {
     return (type->type == HLSL_CLASS_SCALAR) || (type->type == HLSL_CLASS_VECTOR && type->dimx == 1);
@@ -2236,6 +2281,8 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
     if (ctx->profile->major_version < 4)
         transform_ir(ctx, lower_division, body, NULL);
 
+    transform_ir(ctx, validate_static_object_references, body, NULL);
+
     /* TODO: move forward, remove when no longer needed */
     transform_ir(ctx, transform_deref_paths_into_offsets, body, NULL);
     while (transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL));
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h
index 8bde552342..aca5606b0d 100644
--- a/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -118,6 +118,7 @@ enum vkd3d_shader_error
     VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS        = 5019,
     VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE        = 5020,
     VKD3D_SHADER_ERROR_HLSL_DIVISION_BY_ZERO            = 5021,
+    VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF       = 5022,
 
     VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION       = 5300,
     VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO          = 5301,
diff --git a/tests/object-references.shader_test b/tests/object-references.shader_test
index c3952e03d3..6cff351a5f 100644
--- a/tests/object-references.shader_test
+++ b/tests/object-references.shader_test
@@ -89,7 +89,7 @@ draw quad
 probe all rgba (2132, 2132, 2132, 1111)
 
 
-[pixel shader fail todo]
+[pixel shader fail]
 Texture2D tex[3];
 uniform int n;
 
@@ -109,7 +109,7 @@ float4 main() : sv_target
 }
 
 
-[pixel shader fail todo]
+[pixel shader fail]
 // Note: Only valid in shader model 5.1
 Texture2D tex[3];
 uniform int n;
-- 
GitLab


From 96a723670093fee604e0171e96553e51a1013c63 Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Tue, 2 Aug 2022 10:29:34 -0400
Subject: [PATCH 10/11] vkd3d-shader/hlsl: Set objects' register size back to
 0.

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 libs/vkd3d-shader/hlsl.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index 38df7e8a4d..f3386e4c15 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -198,7 +198,6 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type
         {
             unsigned int element_size = type->e.array.type->reg_size;
 
-            assert(element_size);
             if (is_sm4)
                 type->reg_size = (type->e.array.elements_count - 1) * align(element_size, 4) + element_size;
             else
@@ -218,8 +217,6 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type
                 struct hlsl_struct_field *field = &type->e.record.fields[i];
                 unsigned int field_size = field->type->reg_size;
 
-                assert(field_size);
-
                 type->reg_size = hlsl_type_get_sm4_offset(field->type, type->reg_size);
                 field->reg_offset = type->reg_size;
                 type->reg_size += field_size;
@@ -230,8 +227,7 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type
         }
 
         case HLSL_CLASS_OBJECT:
-            /* For convenience when performing copy propagation. */
-            type->reg_size = 1;
+            type->reg_size = 0;
             break;
     }
 }
-- 
GitLab


From 3d9baef321cb73ddbfbea09c06cc99e72f1425dc Mon Sep 17 00:00:00 2001
From: Francisco Casas <fcasas@codeweavers.com>
Date: Mon, 8 Aug 2022 18:11:03 -0400
Subject: [PATCH 11/11] vkd3d-shader/hlsl: Support initialization of implicit
 size arrays.

HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT (zero) is used as a temporal value
for elements_count for implicit size arrays.
This value is replaced by the correct one after parsing the initializer.

In case the implicit array is not initialized correctly, hlsl_error()
is called but the array size is kept at 0. So the rest of the code
must handle these cases.

In shader model 5.1, unlike in 5.0, declaring a multi-dimensional
object-type array with the last dimension implicit results in
an error. This happens even in presence of an initializer.

So, both gen_struct_fields() and declare_vars() first check if the
shader model is 5.1, the array elements are objects, and if there is
at least one implicit array size to handle the whole type as an
unbounded resource array.

Signed-off-by: Francisco Casas <fcasas@codeweavers.com>
---
 libs/vkd3d-shader/hlsl.c                      |  11 +-
 libs/vkd3d-shader/hlsl.h                      |   2 +
 libs/vkd3d-shader/hlsl.y                      | 144 +++++++++++++++++-
 ...lsl-initializer-implicit-array.shader_test |  16 +-
 4 files changed, 158 insertions(+), 15 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index f3386e4c15..2b5222dbaf 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -198,7 +198,9 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type
         {
             unsigned int element_size = type->e.array.type->reg_size;
 
-            if (is_sm4)
+            if (type->e.array.elements_count == HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT)
+                type->reg_size = 0;
+            else if (is_sm4)
                 type->reg_size = (type->e.array.elements_count - 1) * align(element_size, 4) + element_size;
             else
                 type->reg_size = type->e.array.elements_count * element_size;
@@ -1313,7 +1315,12 @@ struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const stru
             }
 
             for (t = type; t->type == HLSL_CLASS_ARRAY; t = t->e.array.type)
-                vkd3d_string_buffer_printf(string, "[%u]", t->e.array.elements_count);
+            {
+                if (t->e.array.elements_count == HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT)
+                    vkd3d_string_buffer_printf(string, "[]");
+                else
+                    vkd3d_string_buffer_printf(string, "[%u]", t->e.array.elements_count);
+            }
             return string;
         }
 
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h
index 54902c3743..d3317bb12b 100644
--- a/libs/vkd3d-shader/hlsl.h
+++ b/libs/vkd3d-shader/hlsl.h
@@ -230,6 +230,8 @@ struct hlsl_src
 
 #define HLSL_MODIFIERS_MAJORITY_MASK (HLSL_MODIFIER_ROW_MAJOR | HLSL_MODIFIER_COLUMN_MAJOR)
 
+#define HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT 0
+
 struct hlsl_reg_reservation
 {
     char type;
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y
index 1e488afaae..91f0ab60a9 100644
--- a/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d-shader/hlsl.y
@@ -853,6 +853,11 @@ static void free_parse_variable_def(struct parse_variable_def *v)
     vkd3d_free(v);
 }
 
+static bool shader_is_sm_5_1(const struct hlsl_ctx *ctx)
+{
+    return ctx->profile->major_version == 5 && ctx->profile->minor_version >= 1;
+}
+
 static bool gen_struct_fields(struct hlsl_ctx *ctx, struct parse_fields *fields,
         struct hlsl_type *type, unsigned int modifiers, struct list *defs)
 {
@@ -870,11 +875,45 @@ static bool gen_struct_fields(struct hlsl_ctx *ctx, struct parse_fields *fields,
     LIST_FOR_EACH_ENTRY_SAFE(v, v_next, defs, struct parse_variable_def, entry)
     {
         struct hlsl_struct_field *field = &fields->fields[i++];
-        unsigned int j;
+        bool unbounded_res_array = false;
+        unsigned int k;
 
         field->type = type;
-        for (j = 0; j < v->arrays.count; ++j)
-            field->type = hlsl_new_array_type(ctx, field->type, v->arrays.sizes[j]);
+
+        if (shader_is_sm_5_1(ctx) && type->type == HLSL_CLASS_OBJECT)
+        {
+            for (k = 0; k < v->arrays.count; ++k)
+                unbounded_res_array |= (v->arrays.sizes[k] == HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT);
+        }
+
+        if (unbounded_res_array)
+        {
+            if (v->arrays.count == 1)
+            {
+                hlsl_fixme(ctx, &v->loc, "Unbounded resource arrays as struct fields.");
+                free_parse_variable_def(v);
+                vkd3d_free(field);
+                continue;
+            }
+            else
+            {
+                hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+                        "Unbounded resource arrays cannot be multi-dimensional.");
+            }
+        }
+        else
+        {
+            for (k = 0; k < v->arrays.count; ++k)
+            {
+                if (v->arrays.sizes[k] == HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT)
+                {
+                    hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+                            "Implicit size arrays not allowed in struct fields.");
+                }
+
+                field->type = hlsl_new_array_type(ctx, field->type, v->arrays.sizes[k]);
+            }
+        }
         vkd3d_free(v->arrays.sizes);
         field->loc = v->loc;
         field->name = v->name;
@@ -916,6 +955,12 @@ static bool add_typedef(struct hlsl_ctx *ctx, DWORD modifiers, struct hlsl_type
         ret = true;
         for (i = 0; i < v->arrays.count; ++i)
         {
+            if (v->arrays.sizes[i] == HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT)
+            {
+                hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+                        "Implicit size arrays not allowed in typedefs.");
+            }
+
             if (!(type = hlsl_new_array_type(ctx, type, v->arrays.sizes[i])))
             {
                 free_parse_variable_def(v);
@@ -1775,11 +1820,78 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t
 
     LIST_FOR_EACH_ENTRY_SAFE(v, v_next, var_list, struct parse_variable_def, entry)
     {
+        bool unbounded_res_array = false;
         unsigned int i;
 
         type = basic_type;
-        for (i = 0; i < v->arrays.count; ++i)
-            type = hlsl_new_array_type(ctx, type, v->arrays.sizes[i]);
+
+        if (shader_is_sm_5_1(ctx) && type->type == HLSL_CLASS_OBJECT)
+        {
+            for (i = 0; i < v->arrays.count; ++i)
+                unbounded_res_array |= (v->arrays.sizes[i] == HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT);
+        }
+
+        if (unbounded_res_array)
+        {
+            if (v->arrays.count == 1)
+            {
+                hlsl_fixme(ctx, &v->loc, "Unbounded resource arrays.");
+                free_parse_variable_def(v);
+                continue;
+            }
+            else
+            {
+                hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+                        "Unbounded resource arrays cannot be multi-dimensional.");
+            }
+        }
+        else
+        {
+            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);
+
+                    if (i < v->arrays.count - 1)
+                    {
+                        hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+                                "Only innermost array size can be implicit.");
+                        free_parse_initializer(&v->initializer);
+                        v->initializer.args_count = 0;
+                    }
+                    else if (elem_components == 0)
+                    {
+                        hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+                                "Cannot declare an implicit size array of a size 0 type.");
+                        free_parse_initializer(&v->initializer);
+                        v->initializer.args_count = 0;
+                    }
+                    else if (size == 0)
+                    {
+                        hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+                                "Implicit size arrays need to be initialized.");
+                        free_parse_initializer(&v->initializer);
+                        v->initializer.args_count = 0;
+
+                    }
+                    else if (size % elem_components != 0)
+                    {
+                        hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT,
+                                "Cannot initialize implicit size array with %u components, expected a multiple of %u.",
+                                size, elem_components);
+                        free_parse_initializer(&v->initializer);
+                        v->initializer.args_count = 0;
+                    }
+                    else
+                    {
+                        v->arrays.sizes[i] = size / elem_components;
+                    }
+                }
+                type = hlsl_new_array_type(ctx, type, v->arrays.sizes[i]);
+            }
+        }
         vkd3d_free(v->arrays.sizes);
 
         if (type->type != HLSL_CLASS_MATRIX)
@@ -3517,6 +3629,21 @@ arrays:
             $$.sizes = new_array;
             $$.sizes[$$.count++] = size;
         }
+    | '[' ']' arrays
+        {
+            uint32_t *new_array;
+
+            $$ = $3;
+
+            if (!(new_array = hlsl_realloc(ctx, $$.sizes, ($$.count + 1) * sizeof(*new_array))))
+            {
+                vkd3d_free($$.sizes);
+                YYABORT;
+            }
+
+            $$.sizes = new_array;
+            $$.sizes[$$.count++] = HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT;
+        }
 
 var_modifiers:
       %empty
@@ -4058,7 +4185,14 @@ unary_expr:
 
             dst_type = $3;
             for (i = 0; i < $4.count; ++i)
+            {
+                if ($4.sizes[i] == HLSL_ARRAY_ELEMENTS_COUNT_IMPLICIT)
+                {
+                    hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+                            "Implicit size arrays not allowed in casts.");
+                }
                 dst_type = hlsl_new_array_type(ctx, dst_type, $4.sizes[i]);
+            }
 
             if (!compatible_data_types(src_type, dst_type))
             {
diff --git a/tests/hlsl-initializer-implicit-array.shader_test b/tests/hlsl-initializer-implicit-array.shader_test
index 648825eb3d..38c8234cbb 100644
--- a/tests/hlsl-initializer-implicit-array.shader_test
+++ b/tests/hlsl-initializer-implicit-array.shader_test
@@ -7,8 +7,8 @@ float4 main() : SV_TARGET
 }
 
 [test]
-todo draw quad
-todo probe all rgba (50, 60, 70, 80)
+draw quad
+probe all rgba (50, 60, 70, 80)
 
 
 [pixel shader]
@@ -21,8 +21,8 @@ float4 main() : sv_target
 }
 
 [test]
-todo draw quad
-todo probe all rgba (5.0, 6.0, 7.0, 8.0)
+draw quad
+probe all rgba (5.0, 6.0, 7.0, 8.0)
 
 
 [pixel shader]
@@ -34,8 +34,8 @@ float4 main() : sv_target
 }
 
 [test]
-todo draw quad
-todo probe all rgba (7.0, 8.0, 9.0, 10.0)
+draw quad
+probe all rgba (7.0, 8.0, 9.0, 10.0)
 
 
 [pixel shader]
@@ -62,8 +62,8 @@ float4 main() : SV_TARGET
 }
 
 [test]
-todo draw quad
-todo probe all rgba (318.0, 320.0, 322.0, 324.0)
+draw quad
+probe all rgba (318.0, 320.0, 322.0, 324.0)
 
 
 [pixel shader fail]
-- 
GitLab