From: Jason Ekstrand Date: Tue, 29 Dec 2015 20:09:32 +0000 (-0800) Subject: nir/spirv: Move CF emit code into vtn_cfg.c X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0a2ab87947083e0a0a7be5a0128f1898d21d5162;p=mesa.git nir/spirv: Move CF emit code into vtn_cfg.c --- diff --git a/src/glsl/nir/spirv/spirv_to_nir.c b/src/glsl/nir/spirv/spirv_to_nir.c index 1539c750036..4a90f1827cf 100644 --- a/src/glsl/nir/spirv/spirv_to_nir.c +++ b/src/glsl/nir/spirv/spirv_to_nir.c @@ -1459,7 +1459,7 @@ static nir_ssa_def * vtn_vector_insert_dynamic(struct vtn_builder *b, nir_ssa_def *src, nir_ssa_def *insert, nir_ssa_def *index); -static void +void vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src, nir_deref_var *dest, struct vtn_type *dest_type) { @@ -3574,226 +3574,6 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, return true; } -/* XXX: This should go in nir_builder.h */ -static inline void -nir_jump(nir_builder *build, nir_jump_type jump_type) -{ - nir_jump_instr *jump = nir_jump_instr_create(build->shader, jump_type); - nir_builder_instr_insert(build, &jump->instr); -} - -static void -vtn_emit_branch(struct vtn_builder *b, enum vtn_branch_type branch_type, - nir_variable *switch_fall_var, bool *has_switch_break) -{ - switch (branch_type) { - case vtn_branch_type_switch_break: - nir_store_var(&b->nb, switch_fall_var, nir_imm_int(&b->nb, NIR_FALSE), 1); - *has_switch_break = true; - break; - case vtn_branch_type_switch_fallthrough: - break; /* Nothing to do */ - case vtn_branch_type_loop_break: - nir_jump(&b->nb, nir_jump_break); - break; - case vtn_branch_type_loop_continue: - nir_jump(&b->nb, nir_jump_continue); - break; - case vtn_branch_type_return: - nir_jump(&b->nb, nir_jump_return); - break; - default: - unreachable("Invalid branch type"); - } -} - -static void -vtn_emit_cf_list(struct vtn_builder *b, struct list_head *cf_list, - nir_variable *switch_fall_var, bool *has_switch_break) -{ - list_for_each_entry(struct vtn_cf_node, node, cf_list, link) { - switch (node->type) { - case vtn_cf_node_type_block: { - struct vtn_block *block = (struct vtn_block *)node; - - block->block = nir_cursor_current_block(b->nb.cursor); - _mesa_hash_table_insert(b->block_table, block->block, block); - - vtn_foreach_instruction(b, block->label, - block->merge ? block->merge : block->branch, - vtn_handle_body_instruction); - - if ((*block->branch & SpvOpCodeMask) == SpvOpReturnValue) { - struct vtn_ssa_value *src = vtn_ssa_value(b, block->branch[1]); - vtn_variable_store(b, src, - nir_deref_var_create(b, b->impl->return_var), - NULL); - } - - if (block->branch_type != vtn_branch_type_none) { - vtn_emit_branch(b, block->branch_type, - switch_fall_var, has_switch_break); - } - - break; - } - - case vtn_cf_node_type_if: { - struct vtn_if *vtn_if = (struct vtn_if *)node; - - nir_if *if_stmt = nir_if_create(b->shader); - if_stmt->condition = - nir_src_for_ssa(vtn_ssa_value(b, vtn_if->condition)->def); - nir_cf_node_insert(b->nb.cursor, &if_stmt->cf_node); - - bool sw_break = false; - - b->nb.cursor = nir_after_cf_list(&if_stmt->then_list); - if (vtn_if->then_type == vtn_branch_type_none) - vtn_emit_cf_list(b, &vtn_if->then_body, switch_fall_var, &sw_break); - else - vtn_emit_branch(b, vtn_if->then_type, switch_fall_var, &sw_break); - - b->nb.cursor = nir_after_cf_list(&if_stmt->else_list); - if (vtn_if->else_type == vtn_branch_type_none) - vtn_emit_cf_list(b, &vtn_if->else_body, switch_fall_var, &sw_break); - else - vtn_emit_branch(b, vtn_if->else_type, switch_fall_var, &sw_break); - - b->nb.cursor = nir_after_cf_node(&if_stmt->cf_node); - - /* If we encountered a switch break somewhere inside of the if, - * then it would have been handled correctly by calling - * emit_cf_list or emit_branch for the interrior. However, we - * need to predicate everything following on wether or not we're - * still going. - */ - if (sw_break) { - *has_switch_break = true; - - nir_if *switch_if = nir_if_create(b->shader); - switch_if->condition = - nir_src_for_ssa(nir_load_var(&b->nb, switch_fall_var)); - nir_cf_node_insert(b->nb.cursor, &switch_if->cf_node); - - b->nb.cursor = nir_after_cf_list(&if_stmt->then_list); - } - break; - } - - case vtn_cf_node_type_loop: { - struct vtn_loop *vtn_loop = (struct vtn_loop *)node; - - nir_loop *loop = nir_loop_create(b->shader); - nir_cf_node_insert(b->nb.cursor, &loop->cf_node); - - if (!list_empty(&vtn_loop->cont_body)) { - /* If we have a non-trivial continue body then we need to put - * it at the beginning of the loop with a flag to ensure that - * it doesn't get executed in the first iteration. - */ - nir_variable *do_cont = - nir_local_variable_create(b->nb.impl, glsl_bool_type(), "cont"); - - b->nb.cursor = nir_before_cf_node(&loop->cf_node); - nir_store_var(&b->nb, do_cont, nir_imm_int(&b->nb, NIR_FALSE), 1); - - b->nb.cursor = nir_after_cf_list(&loop->body); - nir_if *cont_if = nir_if_create(b->shader); - cont_if->condition = nir_src_for_ssa(nir_load_var(&b->nb, do_cont)); - nir_cf_node_insert(b->nb.cursor, &cont_if->cf_node); - - b->nb.cursor = nir_after_cf_list(&cont_if->then_list); - vtn_emit_cf_list(b, &vtn_loop->cont_body, NULL, NULL); - - b->nb.cursor = nir_after_cf_node(&cont_if->cf_node); - nir_store_var(&b->nb, do_cont, nir_imm_int(&b->nb, NIR_TRUE), 1); - } - - b->nb.cursor = nir_after_cf_list(&loop->body); - vtn_emit_cf_list(b, &vtn_loop->body, NULL, NULL); - - b->nb.cursor = nir_after_cf_node(&loop->cf_node); - break; - } - - case vtn_cf_node_type_switch: { - struct vtn_switch *vtn_switch = (struct vtn_switch *)node; - - /* First, we create a variable to keep track of whether or not the - * switch is still going at any given point. Any switch breaks - * will set this variable to false. - */ - nir_variable *fall_var = - nir_local_variable_create(b->nb.impl, glsl_bool_type(), "fall"); - nir_store_var(&b->nb, fall_var, nir_imm_int(&b->nb, NIR_TRUE), 1); - - /* Next, we gather up all of the conditions. We have to do this - * up-front because we also need to build an "any" condition so - * that we can use !any for default. - */ - const int num_cases = list_length(&vtn_switch->cases); - NIR_VLA(nir_ssa_def *, conditions, num_cases); - - nir_ssa_def *sel = vtn_ssa_value(b, vtn_switch->selector)->def; - /* An accumulation of all conditions. Used for the default */ - nir_ssa_def *any = NULL; - - int i = 0; - list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) { - if (cse->is_default) { - conditions[i++] = NULL; - continue; - } - - nir_ssa_def *cond = NULL; - nir_array_foreach(&cse->values, uint32_t, val) { - nir_ssa_def *is_val = - nir_ieq(&b->nb, sel, nir_imm_int(&b->nb, *val)); - - cond = cond ? nir_ior(&b->nb, cond, is_val) : is_val; - } - - any = any ? nir_ior(&b->nb, any, cond) : cond; - conditions[i++] = cond; - } - assert(i == num_cases); - - /* Now we can walk the list of cases and actually emit code */ - i = 0; - list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) { - /* Figure out the condition */ - nir_ssa_def *cond = conditions[i++]; - if (cse->is_default) { - assert(cond == NULL); - cond = nir_inot(&b->nb, any); - } - /* Take fallthrough into account */ - cond = nir_ior(&b->nb, cond, nir_load_var(&b->nb, fall_var)); - - nir_if *case_if = nir_if_create(b->nb.shader); - case_if->condition = nir_src_for_ssa(cond); - nir_cf_node_insert(b->nb.cursor, &case_if->cf_node); - - bool has_break = false; - b->nb.cursor = nir_after_cf_list(&case_if->then_list); - vtn_emit_cf_list(b, &cse->body, fall_var, &has_break); - (void)has_break; /* We don't care */ - - b->nb.cursor = nir_after_cf_node(&case_if->cf_node); - } - assert(i == num_cases); - - break; - } - - default: - unreachable("Invalid CF node type"); - } - } -} - - nir_shader * spirv_to_nir(const uint32_t *words, size_t word_count, gl_shader_stage stage, @@ -3839,9 +3619,7 @@ spirv_to_nir(const uint32_t *words, size_t word_count, _mesa_key_pointer_equal); b->block_table = _mesa_hash_table_create(b, _mesa_hash_pointer, _mesa_key_pointer_equal); - nir_builder_init(&b->nb, b->impl); - b->nb.cursor = nir_after_cf_list(&b->impl->body); - vtn_emit_cf_list(b, &func->body, NULL, NULL); + vtn_function_emit(b, func, vtn_handle_body_instruction); vtn_foreach_instruction(b, func->start_block->label, func->end, vtn_handle_phi_second_pass); } diff --git a/src/glsl/nir/spirv/vtn_cfg.c b/src/glsl/nir/spirv/vtn_cfg.c index 9d8d451b5e0..7d25e96c8f0 100644 --- a/src/glsl/nir/spirv/vtn_cfg.c +++ b/src/glsl/nir/spirv/vtn_cfg.c @@ -22,6 +22,7 @@ */ #include "vtn_private.h" +#include "nir/nir_vla.h" static bool vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode, @@ -448,3 +449,236 @@ vtn_build_cfg(struct vtn_builder *b, const uint32_t *words, const uint32_t *end) NULL, NULL, NULL, NULL, NULL); } } + +/* XXX: This should go in nir_builder.h */ +static inline void +nir_jump(nir_builder *build, nir_jump_type jump_type) +{ + nir_jump_instr *jump = nir_jump_instr_create(build->shader, jump_type); + nir_builder_instr_insert(build, &jump->instr); +} + +static void +vtn_emit_branch(struct vtn_builder *b, enum vtn_branch_type branch_type, + nir_variable *switch_fall_var, bool *has_switch_break) +{ + switch (branch_type) { + case vtn_branch_type_switch_break: + nir_store_var(&b->nb, switch_fall_var, nir_imm_int(&b->nb, NIR_FALSE), 1); + *has_switch_break = true; + break; + case vtn_branch_type_switch_fallthrough: + break; /* Nothing to do */ + case vtn_branch_type_loop_break: + nir_jump(&b->nb, nir_jump_break); + break; + case vtn_branch_type_loop_continue: + nir_jump(&b->nb, nir_jump_continue); + break; + case vtn_branch_type_return: + nir_jump(&b->nb, nir_jump_return); + break; + default: + unreachable("Invalid branch type"); + } +} + +static void +vtn_emit_cf_list(struct vtn_builder *b, struct list_head *cf_list, + nir_variable *switch_fall_var, bool *has_switch_break, + vtn_instruction_handler handler) +{ + list_for_each_entry(struct vtn_cf_node, node, cf_list, link) { + switch (node->type) { + case vtn_cf_node_type_block: { + struct vtn_block *block = (struct vtn_block *)node; + + block->block = nir_cursor_current_block(b->nb.cursor); + _mesa_hash_table_insert(b->block_table, block->block, block); + + vtn_foreach_instruction(b, block->label, + block->merge ? block->merge : block->branch, + handler); + + if ((*block->branch & SpvOpCodeMask) == SpvOpReturnValue) { + struct vtn_ssa_value *src = vtn_ssa_value(b, block->branch[1]); + vtn_variable_store(b, src, + nir_deref_var_create(b, b->impl->return_var), + NULL); + } + + if (block->branch_type != vtn_branch_type_none) { + vtn_emit_branch(b, block->branch_type, + switch_fall_var, has_switch_break); + } + + break; + } + + case vtn_cf_node_type_if: { + struct vtn_if *vtn_if = (struct vtn_if *)node; + + nir_if *if_stmt = nir_if_create(b->shader); + if_stmt->condition = + nir_src_for_ssa(vtn_ssa_value(b, vtn_if->condition)->def); + nir_cf_node_insert(b->nb.cursor, &if_stmt->cf_node); + + bool sw_break = false; + + b->nb.cursor = nir_after_cf_list(&if_stmt->then_list); + if (vtn_if->then_type == vtn_branch_type_none) { + vtn_emit_cf_list(b, &vtn_if->then_body, + switch_fall_var, &sw_break, handler); + } else { + vtn_emit_branch(b, vtn_if->then_type, switch_fall_var, &sw_break); + } + + b->nb.cursor = nir_after_cf_list(&if_stmt->else_list); + if (vtn_if->else_type == vtn_branch_type_none) { + vtn_emit_cf_list(b, &vtn_if->else_body, + switch_fall_var, &sw_break, handler); + } else { + vtn_emit_branch(b, vtn_if->else_type, switch_fall_var, &sw_break); + } + + b->nb.cursor = nir_after_cf_node(&if_stmt->cf_node); + + /* If we encountered a switch break somewhere inside of the if, + * then it would have been handled correctly by calling + * emit_cf_list or emit_branch for the interrior. However, we + * need to predicate everything following on wether or not we're + * still going. + */ + if (sw_break) { + *has_switch_break = true; + + nir_if *switch_if = nir_if_create(b->shader); + switch_if->condition = + nir_src_for_ssa(nir_load_var(&b->nb, switch_fall_var)); + nir_cf_node_insert(b->nb.cursor, &switch_if->cf_node); + + b->nb.cursor = nir_after_cf_list(&if_stmt->then_list); + } + break; + } + + case vtn_cf_node_type_loop: { + struct vtn_loop *vtn_loop = (struct vtn_loop *)node; + + nir_loop *loop = nir_loop_create(b->shader); + nir_cf_node_insert(b->nb.cursor, &loop->cf_node); + + if (!list_empty(&vtn_loop->cont_body)) { + /* If we have a non-trivial continue body then we need to put + * it at the beginning of the loop with a flag to ensure that + * it doesn't get executed in the first iteration. + */ + nir_variable *do_cont = + nir_local_variable_create(b->nb.impl, glsl_bool_type(), "cont"); + + b->nb.cursor = nir_before_cf_node(&loop->cf_node); + nir_store_var(&b->nb, do_cont, nir_imm_int(&b->nb, NIR_FALSE), 1); + + b->nb.cursor = nir_after_cf_list(&loop->body); + nir_if *cont_if = nir_if_create(b->shader); + cont_if->condition = nir_src_for_ssa(nir_load_var(&b->nb, do_cont)); + nir_cf_node_insert(b->nb.cursor, &cont_if->cf_node); + + b->nb.cursor = nir_after_cf_list(&cont_if->then_list); + vtn_emit_cf_list(b, &vtn_loop->cont_body, NULL, NULL, handler); + + b->nb.cursor = nir_after_cf_node(&cont_if->cf_node); + nir_store_var(&b->nb, do_cont, nir_imm_int(&b->nb, NIR_TRUE), 1); + } + + b->nb.cursor = nir_after_cf_list(&loop->body); + vtn_emit_cf_list(b, &vtn_loop->body, NULL, NULL, handler); + + b->nb.cursor = nir_after_cf_node(&loop->cf_node); + break; + } + + case vtn_cf_node_type_switch: { + struct vtn_switch *vtn_switch = (struct vtn_switch *)node; + + /* First, we create a variable to keep track of whether or not the + * switch is still going at any given point. Any switch breaks + * will set this variable to false. + */ + nir_variable *fall_var = + nir_local_variable_create(b->nb.impl, glsl_bool_type(), "fall"); + nir_store_var(&b->nb, fall_var, nir_imm_int(&b->nb, NIR_TRUE), 1); + + /* Next, we gather up all of the conditions. We have to do this + * up-front because we also need to build an "any" condition so + * that we can use !any for default. + */ + const int num_cases = list_length(&vtn_switch->cases); + NIR_VLA(nir_ssa_def *, conditions, num_cases); + + nir_ssa_def *sel = vtn_ssa_value(b, vtn_switch->selector)->def; + /* An accumulation of all conditions. Used for the default */ + nir_ssa_def *any = NULL; + + int i = 0; + list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) { + if (cse->is_default) { + conditions[i++] = NULL; + continue; + } + + nir_ssa_def *cond = NULL; + nir_array_foreach(&cse->values, uint32_t, val) { + nir_ssa_def *is_val = + nir_ieq(&b->nb, sel, nir_imm_int(&b->nb, *val)); + + cond = cond ? nir_ior(&b->nb, cond, is_val) : is_val; + } + + any = any ? nir_ior(&b->nb, any, cond) : cond; + conditions[i++] = cond; + } + assert(i == num_cases); + + /* Now we can walk the list of cases and actually emit code */ + i = 0; + list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) { + /* Figure out the condition */ + nir_ssa_def *cond = conditions[i++]; + if (cse->is_default) { + assert(cond == NULL); + cond = nir_inot(&b->nb, any); + } + /* Take fallthrough into account */ + cond = nir_ior(&b->nb, cond, nir_load_var(&b->nb, fall_var)); + + nir_if *case_if = nir_if_create(b->nb.shader); + case_if->condition = nir_src_for_ssa(cond); + nir_cf_node_insert(b->nb.cursor, &case_if->cf_node); + + bool has_break = false; + b->nb.cursor = nir_after_cf_list(&case_if->then_list); + vtn_emit_cf_list(b, &cse->body, fall_var, &has_break, handler); + (void)has_break; /* We don't care */ + + b->nb.cursor = nir_after_cf_node(&case_if->cf_node); + } + assert(i == num_cases); + + break; + } + + default: + unreachable("Invalid CF node type"); + } + } +} + +void +vtn_function_emit(struct vtn_builder *b, struct vtn_function *func, + vtn_instruction_handler instruction_handler) +{ + nir_builder_init(&b->nb, func->impl); + b->nb.cursor = nir_after_cf_list(&func->impl->body); + vtn_emit_cf_list(b, &func->body, NULL, NULL, instruction_handler); +} diff --git a/src/glsl/nir/spirv/vtn_private.h b/src/glsl/nir/spirv/vtn_private.h index 6dfd01d5c24..7ed62ee712b 100644 --- a/src/glsl/nir/spirv/vtn_private.h +++ b/src/glsl/nir/spirv/vtn_private.h @@ -162,12 +162,14 @@ struct vtn_function { SpvFunctionControlMask control; }; -void vtn_build_cfg(struct vtn_builder *b, const uint32_t *words, - const uint32_t *end); - typedef bool (*vtn_instruction_handler)(struct vtn_builder *, uint32_t, const uint32_t *, unsigned); +void vtn_build_cfg(struct vtn_builder *b, const uint32_t *words, + const uint32_t *end); +void vtn_function_emit(struct vtn_builder *b, struct vtn_function *func, + vtn_instruction_handler instruction_handler); + const uint32_t * vtn_foreach_instruction(struct vtn_builder *b, const uint32_t *start, const uint32_t *end, vtn_instruction_handler handler); @@ -342,6 +344,10 @@ vtn_value(struct vtn_builder *b, uint32_t value_id, struct vtn_ssa_value *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id); +void vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src, + nir_deref_var *dest, struct vtn_type *dest_type); + + typedef void (*vtn_decoration_foreach_cb)(struct vtn_builder *, struct vtn_value *, int member,