Module: vkd3d
Branch: master
Commit: 9ac842b36b8bfa8e2f79b4200feae0fa105ad6e1
URL: https://gitlab.winehq.org/wine/vkd3d/-/commit/9ac842b36b8bfa8e2f79b4200feae…
Author: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Date: Tue Jan 30 15:55:12 2024 +0100
vkd3d-shader/ir: Compute the loops in the control flow graph.
---
include/vkd3d_types.h | 2 ++
libs/vkd3d-shader/ir.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/include/vkd3d_types.h b/include/vkd3d_types.h
index 4a7aca23..9060fa08 100644
--- a/include/vkd3d_types.h
+++ b/include/vkd3d_types.h
@@ -41,6 +41,8 @@ enum vkd3d_result
{
/** Success. */
VKD3D_OK = 0,
+ /** Success as a result of there being nothing to do. */
+ VKD3D_FALSE = 1,
/** An unspecified failure occurred. */
VKD3D_ERROR = -1,
/** There are not enough resources available to complete the operation. */
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c
index 4ffdd0cb..05997241 100644
--- a/libs/vkd3d-shader/ir.c
+++ b/libs/vkd3d-shader/ir.c
@@ -3038,7 +3038,7 @@ static enum vkd3d_result vsir_block_list_add(struct vsir_block_list *list, struc
for (i = 0; i < list->count; ++i)
if (block == list->blocks[i])
- return VKD3D_OK;
+ return VKD3D_FALSE;
if (!vkd3d_array_reserve((void **)&list->blocks, &list->capacity, list->count + 1, sizeof(*list->blocks)))
{
@@ -3103,6 +3103,9 @@ struct vsir_cfg
struct vsir_block *entry;
size_t block_count;
struct vkd3d_string_buffer debug_buffer;
+
+ struct vsir_block_list *loops;
+ size_t loops_count, loops_capacity;
};
static void vsir_cfg_cleanup(struct vsir_cfg *cfg)
@@ -3112,7 +3115,11 @@ static void vsir_cfg_cleanup(struct vsir_cfg *cfg)
for (i = 0; i < cfg->block_count; ++i)
vsir_block_cleanup(&cfg->blocks[i]);
+ for (i = 0; i < cfg->loops_count; ++i)
+ vsir_block_list_cleanup(&cfg->loops[i]);
+
vkd3d_free(cfg->blocks);
+ vkd3d_free(cfg->loops);
if (TRACE_ON())
vkd3d_string_buffer_cleanup(&cfg->debug_buffer);
@@ -3334,6 +3341,84 @@ static void vsir_cfg_compute_dominators(struct vsir_cfg *cfg)
}
}
+/* A back edge is an edge X -> Y for which block Y dominates block
+ * X. All the other edges are forward edges, and it is required that
+ * the input CFG is reducible, i.e., it is acyclic once you strip away
+ * the back edges.
+ *
+ * Each back edge X -> Y defines a loop: block X is the header block,
+ * block Y is the back edge block, and the loop consists of all the
+ * blocks which are dominated by the header block and have a path to
+ * the back edge block that doesn't pass through the header block
+ * (including the header block itself). It can be proved that all the
+ * blocks in such a path (connecting a loop block to the back edge
+ * block without passing through the header block) belong to the same
+ * loop.
+ *
+ * If the input CFG is reducible, each two loops are either disjoint
+ * or one is a strict subset of the other, provided that each block
+ * has at most one incoming back edge. If this condition does not
+ * hold, a synthetic block can be introduced as the only back edge
+ * block for the given header block, with all the previous back edge
+ * now being forward edges to the synthetic block. This is not
+ * currently implemented (but it is rarely found in practice
+ * anyway). */
+static enum vkd3d_result vsir_cfg_scan_loop(struct vsir_block_list *loop, struct vsir_block *block,
+ struct vsir_block *header)
+{
+ enum vkd3d_result ret;
+ size_t i;
+
+ if ((ret = vsir_block_list_add(loop, block)) < 0)
+ return ret;
+
+ if (ret == VKD3D_FALSE || block == header)
+ return VKD3D_OK;
+
+ for (i = 0; i < block->predecessors.count; ++i)
+ {
+ if ((ret = vsir_cfg_scan_loop(loop, block->predecessors.blocks[i], header)) < 0)
+ return ret;
+ }
+
+ return VKD3D_OK;
+}
+
+static enum vkd3d_result vsir_cfg_compute_loops(struct vsir_cfg *cfg)
+{
+ size_t i, j;
+
+ for (i = 0; i < cfg->block_count; ++i)
+ {
+ struct vsir_block *block = &cfg->blocks[i];
+
+ if (block->label == 0)
+ continue;
+
+ for (j = 0; j < block->successors.count; ++j)
+ {
+ struct vsir_block *header = block->successors.blocks[j];
+ struct vsir_block_list *loop;
+ enum vkd3d_result ret;
+
+ /* Is this a back edge? */
+ if (!vsir_block_dominates(header, block))
+ continue;
+
+ if (!vkd3d_array_reserve((void **)&cfg->loops, &cfg->loops_capacity, cfg->loops_count + 1, sizeof(*cfg->loops)))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ loop = &cfg->loops[cfg->loops_count++];
+ vsir_block_list_init(loop);
+
+ if ((ret = vsir_cfg_scan_loop(loop, block, header)) < 0)
+ return ret;
+ }
+ }
+
+ return VKD3D_OK;
+}
+
enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser,
const struct vkd3d_shader_compile_info *compile_info)
{
@@ -3360,6 +3445,12 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser,
vsir_cfg_compute_dominators(&cfg);
+ if ((result = vsir_cfg_compute_loops(&cfg)) < 0)
+ {
+ vsir_cfg_cleanup(&cfg);
+ return result;
+ }
+
if ((result = simple_structurizer_run(parser)) < 0)
{
vsir_cfg_cleanup(&cfg);
Module: vkd3d
Branch: master
Commit: c5893288d9d8c49dfdbcd927cc94cb993a326d13
URL: https://gitlab.winehq.org/wine/vkd3d/-/commit/c5893288d9d8c49dfdbcd927cc94c…
Author: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Date: Tue Feb 20 15:44:23 2024 +0100
vkd3d-shader/ir: Properly handle function-local indexable temps when flattening control flow.
They have to be considered code rather than declarations, as required
for instance by the SPIR-V backend.
---
libs/vkd3d-shader/ir.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c
index f0bd8533..a379ba6d 100644
--- a/libs/vkd3d-shader/ir.c
+++ b/libs/vkd3d-shader/ir.c
@@ -2041,12 +2041,19 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte
flattener->location = instruction->location;
/* Declarations should occur before the first code block, which in hull shaders is marked by the first
- * phase instruction, and in all other shader types begins with the first label instruction. */
- if (!after_declarations_section && !vsir_instruction_is_dcl(instruction)
- && instruction->handler_idx != VKD3DSIH_NOP)
+ * phase instruction, and in all other shader types begins with the first label instruction.
+ * Declaring an indexable temp with function scope is not considered a declaration,
+ * because it needs to live inside a function. */
+ if (!after_declarations_section && instruction->handler_idx != VKD3DSIH_NOP)
{
- after_declarations_section = true;
- cf_flattener_emit_label(flattener, cf_flattener_alloc_block_id(flattener));
+ bool is_function_indexable = instruction->handler_idx == VKD3DSIH_DCL_INDEXABLE_TEMP
+ && instruction->declaration.indexable_temp.has_function_scope;
+
+ if (!vsir_instruction_is_dcl(instruction) || is_function_indexable)
+ {
+ after_declarations_section = true;
+ cf_flattener_emit_label(flattener, cf_flattener_alloc_block_id(flattener));
+ }
}
cf_info = flattener->control_flow_depth