nir: add Continue Construct to nir_loop

The added continue_list corresponds to the SPIR-V
Continue Construct and serves as a converged control-flow
construct and is executed after each continue statement
and before the next iteration of the loop body.

Also adds validation rules for loops with Continue Construct

Reviewed-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13962>
This commit is contained in:
Daniel Schürmann
2021-12-01 17:34:48 +01:00
committed by Marge Bot
parent e0c6ad1ce5
commit d4b97bf3fa
7 changed files with 126 additions and 19 deletions
+26 -5
View File
@@ -77,6 +77,9 @@ typedef struct {
/* the current loop being visited */
nir_loop *loop;
/* weather the loop continue construct is being visited */
bool in_loop_continue_construct;
/* the parent of the current cf node being visited */
nir_cf_node *parent_node;
@@ -1073,6 +1076,7 @@ validate_jump_instr(nir_jump_instr *instr, validate_state *state)
validate_assert(state, block->successors[1] == NULL);
validate_assert(state, instr->target == NULL);
validate_assert(state, instr->else_target == NULL);
validate_assert(state, !state->in_loop_continue_construct);
break;
case nir_jump_break:
@@ -1092,12 +1096,13 @@ validate_jump_instr(nir_jump_instr *instr, validate_state *state)
validate_assert(state, state->impl->structured);
validate_assert(state, state->loop != NULL);
if (state->loop) {
nir_block *first = nir_loop_first_block(state->loop);
validate_assert(state, block->successors[0] == first);
nir_block *cont_block = nir_loop_continue_target(state->loop);
validate_assert(state, block->successors[0] == cont_block);
}
validate_assert(state, block->successors[1] == NULL);
validate_assert(state, instr->target == NULL);
validate_assert(state, instr->else_target == NULL);
validate_assert(state, !state->in_loop_continue_construct);
break;
case nir_jump_goto:
@@ -1242,6 +1247,7 @@ collect_blocks(struct exec_list *cf_list, validate_state *state)
case nir_cf_node_loop:
collect_blocks(&nir_cf_node_as_loop(node)->body, state);
collect_blocks(&nir_cf_node_as_loop(node)->continue_list, state);
break;
default:
@@ -1310,8 +1316,15 @@ validate_block(nir_block *block, validate_state *state)
if (next == NULL) {
switch (state->parent_node->type) {
case nir_cf_node_loop: {
nir_block *first = nir_loop_first_block(state->loop);
validate_assert(state, block->successors[0] == first);
if (block == nir_loop_last_block(state->loop)) {
nir_block *cont = nir_loop_continue_target(state->loop);
validate_assert(state, block->successors[0] == cont);
} else {
validate_assert(state, nir_loop_has_continue_construct(state->loop) &&
block == nir_loop_last_continue_block(state->loop));
nir_block *head = nir_loop_first_block(state->loop);
validate_assert(state, block->successors[0] == head);
}
/* due to the hack for infinite loops, block->successors[1] may
* point to the block after the loop.
*/
@@ -1421,14 +1434,21 @@ validate_loop(nir_loop *loop, validate_state *state)
nir_cf_node *old_parent = state->parent_node;
state->parent_node = &loop->cf_node;
nir_loop *old_loop = state->loop;
bool old_continue_construct = state->in_loop_continue_construct;
state->loop = loop;
state->in_loop_continue_construct = false;
foreach_list_typed(nir_cf_node, cf_node, node, &loop->body) {
validate_cf_node(cf_node, state);
}
state->in_loop_continue_construct = true;
foreach_list_typed(nir_cf_node, cf_node, node, &loop->continue_list) {
validate_cf_node(cf_node, state);
}
state->in_loop_continue_construct = false;
state->parent_node = old_parent;
state->loop = old_loop;
state->in_loop_continue_construct = old_continue_construct;
}
static void
@@ -1742,6 +1762,7 @@ init_validate_state(validate_state *state)
state->errors = _mesa_pointer_hash_table_create(state->mem_ctx);
state->loop = NULL;
state->in_loop_continue_construct = false;
state->instr = NULL;
state->var = NULL;
}