101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2015 Intel Corporation 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg#include "vtn_private.h" 257ec681f3Smrg#include "spirv_info.h" 2601e04c3fSmrg#include "nir/nir_vla.h" 277ec681f3Smrg#include "util/debug.h" 2801e04c3fSmrg 297ec681f3Smrgstatic struct vtn_block * 307ec681f3Smrgvtn_block(struct vtn_builder *b, uint32_t value_id) 3101e04c3fSmrg{ 327ec681f3Smrg return vtn_value(b, value_id, vtn_value_type_block)->block; 3301e04c3fSmrg} 3401e04c3fSmrg 3501e04c3fSmrgstatic unsigned 367ec681f3Smrgglsl_type_count_function_params(const struct glsl_type *type) 3701e04c3fSmrg{ 387ec681f3Smrg if (glsl_type_is_vector_or_scalar(type)) { 397ec681f3Smrg return 1; 407ec681f3Smrg } else if (glsl_type_is_array_or_matrix(type)) { 417ec681f3Smrg return glsl_get_length(type) * 427ec681f3Smrg glsl_type_count_function_params(glsl_get_array_element(type)); 437ec681f3Smrg } else { 447ec681f3Smrg assert(glsl_type_is_struct_or_ifc(type)); 4501e04c3fSmrg unsigned count = 0; 467ec681f3Smrg unsigned elems = glsl_get_length(type); 477ec681f3Smrg for (unsigned i = 0; i < elems; i++) { 487ec681f3Smrg const struct glsl_type *elem_type = glsl_get_struct_field(type, i); 497ec681f3Smrg count += glsl_type_count_function_params(elem_type); 507ec681f3Smrg } 5101e04c3fSmrg return count; 5201e04c3fSmrg } 5301e04c3fSmrg} 5401e04c3fSmrg 5501e04c3fSmrgstatic void 567ec681f3Smrgglsl_type_add_to_function_params(const struct glsl_type *type, 577ec681f3Smrg nir_function *func, 587ec681f3Smrg unsigned *param_idx) 5901e04c3fSmrg{ 607ec681f3Smrg if (glsl_type_is_vector_or_scalar(type)) { 6101e04c3fSmrg func->params[(*param_idx)++] = (nir_parameter) { 627ec681f3Smrg .num_components = glsl_get_vector_elements(type), 637ec681f3Smrg .bit_size = glsl_get_bit_size(type), 6401e04c3fSmrg }; 657ec681f3Smrg } else if (glsl_type_is_array_or_matrix(type)) { 667ec681f3Smrg unsigned elems = glsl_get_length(type); 677ec681f3Smrg const struct glsl_type *elem_type = glsl_get_array_element(type); 687ec681f3Smrg for (unsigned i = 0; i < elems; i++) 697ec681f3Smrg glsl_type_add_to_function_params(elem_type,func, param_idx); 707ec681f3Smrg } else { 717ec681f3Smrg assert(glsl_type_is_struct_or_ifc(type)); 727ec681f3Smrg unsigned elems = glsl_get_length(type); 737ec681f3Smrg for (unsigned i = 0; i < elems; i++) { 747ec681f3Smrg const struct glsl_type *elem_type = glsl_get_struct_field(type, i); 757ec681f3Smrg glsl_type_add_to_function_params(elem_type, func, param_idx); 767ec681f3Smrg } 7701e04c3fSmrg } 7801e04c3fSmrg} 7901e04c3fSmrg 8001e04c3fSmrgstatic void 8101e04c3fSmrgvtn_ssa_value_add_to_call_params(struct vtn_builder *b, 8201e04c3fSmrg struct vtn_ssa_value *value, 8301e04c3fSmrg nir_call_instr *call, 8401e04c3fSmrg unsigned *param_idx) 8501e04c3fSmrg{ 867ec681f3Smrg if (glsl_type_is_vector_or_scalar(value->type)) { 877ec681f3Smrg call->params[(*param_idx)++] = nir_src_for_ssa(value->def); 887ec681f3Smrg } else { 897ec681f3Smrg unsigned elems = glsl_get_length(value->type); 907ec681f3Smrg for (unsigned i = 0; i < elems; i++) { 9101e04c3fSmrg vtn_ssa_value_add_to_call_params(b, value->elems[i], 9201e04c3fSmrg call, param_idx); 9301e04c3fSmrg } 9401e04c3fSmrg } 9501e04c3fSmrg} 9601e04c3fSmrg 9701e04c3fSmrgstatic void 9801e04c3fSmrgvtn_ssa_value_load_function_param(struct vtn_builder *b, 9901e04c3fSmrg struct vtn_ssa_value *value, 10001e04c3fSmrg unsigned *param_idx) 10101e04c3fSmrg{ 1027ec681f3Smrg if (glsl_type_is_vector_or_scalar(value->type)) { 10301e04c3fSmrg value->def = nir_load_param(&b->nb, (*param_idx)++); 1047ec681f3Smrg } else { 1057ec681f3Smrg unsigned elems = glsl_get_length(value->type); 1067ec681f3Smrg for (unsigned i = 0; i < elems; i++) 1077ec681f3Smrg vtn_ssa_value_load_function_param(b, value->elems[i], param_idx); 10801e04c3fSmrg } 10901e04c3fSmrg} 11001e04c3fSmrg 11101e04c3fSmrgvoid 11201e04c3fSmrgvtn_handle_function_call(struct vtn_builder *b, SpvOp opcode, 11301e04c3fSmrg const uint32_t *w, unsigned count) 11401e04c3fSmrg{ 11501e04c3fSmrg struct vtn_function *vtn_callee = 11601e04c3fSmrg vtn_value(b, w[3], vtn_value_type_function)->func; 11701e04c3fSmrg 11801e04c3fSmrg vtn_callee->referenced = true; 11901e04c3fSmrg 1207ec681f3Smrg nir_call_instr *call = nir_call_instr_create(b->nb.shader, 1217ec681f3Smrg vtn_callee->nir_func); 12201e04c3fSmrg 12301e04c3fSmrg unsigned param_idx = 0; 12401e04c3fSmrg 12501e04c3fSmrg nir_deref_instr *ret_deref = NULL; 12601e04c3fSmrg struct vtn_type *ret_type = vtn_callee->type->return_type; 12701e04c3fSmrg if (ret_type->base_type != vtn_base_type_void) { 12801e04c3fSmrg nir_variable *ret_tmp = 1297e102996Smaya nir_local_variable_create(b->nb.impl, 1307e102996Smaya glsl_get_bare_type(ret_type->type), 1317e102996Smaya "return_tmp"); 13201e04c3fSmrg ret_deref = nir_build_deref_var(&b->nb, ret_tmp); 13301e04c3fSmrg call->params[param_idx++] = nir_src_for_ssa(&ret_deref->dest.ssa); 13401e04c3fSmrg } 13501e04c3fSmrg 13601e04c3fSmrg for (unsigned i = 0; i < vtn_callee->type->length; i++) { 1377ec681f3Smrg vtn_ssa_value_add_to_call_params(b, vtn_ssa_value(b, w[4 + i]), 1387ec681f3Smrg call, ¶m_idx); 13901e04c3fSmrg } 14001e04c3fSmrg assert(param_idx == call->num_params); 14101e04c3fSmrg 14201e04c3fSmrg nir_builder_instr_insert(&b->nb, &call->instr); 14301e04c3fSmrg 14401e04c3fSmrg if (ret_type->base_type == vtn_base_type_void) { 14501e04c3fSmrg vtn_push_value(b, w[2], vtn_value_type_undef); 14601e04c3fSmrg } else { 1477ec681f3Smrg vtn_push_ssa_value(b, w[2], vtn_local_load(b, ret_deref, 0)); 14801e04c3fSmrg } 14901e04c3fSmrg} 15001e04c3fSmrg 15101e04c3fSmrgstatic bool 15201e04c3fSmrgvtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode, 15301e04c3fSmrg const uint32_t *w, unsigned count) 15401e04c3fSmrg{ 15501e04c3fSmrg switch (opcode) { 15601e04c3fSmrg case SpvOpFunction: { 15701e04c3fSmrg vtn_assert(b->func == NULL); 15801e04c3fSmrg b->func = rzalloc(b, struct vtn_function); 15901e04c3fSmrg 1607ec681f3Smrg b->func->node.type = vtn_cf_node_type_function; 1617ec681f3Smrg b->func->node.parent = NULL; 16201e04c3fSmrg list_inithead(&b->func->body); 16301e04c3fSmrg b->func->control = w[3]; 16401e04c3fSmrg 1657ec681f3Smrg UNUSED const struct glsl_type *result_type = vtn_get_type(b, w[1])->type; 16601e04c3fSmrg struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_function); 16701e04c3fSmrg val->func = b->func; 16801e04c3fSmrg 1697ec681f3Smrg b->func->type = vtn_get_type(b, w[4]); 17001e04c3fSmrg const struct vtn_type *func_type = b->func->type; 17101e04c3fSmrg 17201e04c3fSmrg vtn_assert(func_type->return_type->type == result_type); 17301e04c3fSmrg 17401e04c3fSmrg nir_function *func = 17501e04c3fSmrg nir_function_create(b->shader, ralloc_strdup(b->shader, val->name)); 17601e04c3fSmrg 17701e04c3fSmrg unsigned num_params = 0; 17801e04c3fSmrg for (unsigned i = 0; i < func_type->length; i++) 1797ec681f3Smrg num_params += glsl_type_count_function_params(func_type->params[i]->type); 18001e04c3fSmrg 18101e04c3fSmrg /* Add one parameter for the function return value */ 18201e04c3fSmrg if (func_type->return_type->base_type != vtn_base_type_void) 18301e04c3fSmrg num_params++; 18401e04c3fSmrg 18501e04c3fSmrg func->num_params = num_params; 18601e04c3fSmrg func->params = ralloc_array(b->shader, nir_parameter, num_params); 18701e04c3fSmrg 18801e04c3fSmrg unsigned idx = 0; 18901e04c3fSmrg if (func_type->return_type->base_type != vtn_base_type_void) { 1907ec681f3Smrg nir_address_format addr_format = 1917ec681f3Smrg vtn_mode_to_address_format(b, vtn_variable_mode_function); 19201e04c3fSmrg /* The return value is a regular pointer */ 19301e04c3fSmrg func->params[idx++] = (nir_parameter) { 1947ec681f3Smrg .num_components = nir_address_format_num_components(addr_format), 1957ec681f3Smrg .bit_size = nir_address_format_bit_size(addr_format), 19601e04c3fSmrg }; 19701e04c3fSmrg } 19801e04c3fSmrg 19901e04c3fSmrg for (unsigned i = 0; i < func_type->length; i++) 2007ec681f3Smrg glsl_type_add_to_function_params(func_type->params[i]->type, func, &idx); 20101e04c3fSmrg assert(idx == num_params); 20201e04c3fSmrg 2037ec681f3Smrg b->func->nir_func = func; 2047ec681f3Smrg 2057ec681f3Smrg /* Set up a nir_function_impl and the builder so we can load arguments 2067ec681f3Smrg * directly in our OpFunctionParameter handler. 2077ec681f3Smrg */ 2087ec681f3Smrg nir_function_impl *impl = nir_function_impl_create(func); 2097ec681f3Smrg nir_builder_init(&b->nb, impl); 2107ec681f3Smrg b->nb.cursor = nir_before_cf_list(&impl->body); 2117e102996Smaya b->nb.exact = b->exact; 21201e04c3fSmrg 21301e04c3fSmrg b->func_param_idx = 0; 21401e04c3fSmrg 21501e04c3fSmrg /* The return value is the first parameter */ 21601e04c3fSmrg if (func_type->return_type->base_type != vtn_base_type_void) 21701e04c3fSmrg b->func_param_idx++; 21801e04c3fSmrg break; 21901e04c3fSmrg } 22001e04c3fSmrg 22101e04c3fSmrg case SpvOpFunctionEnd: 22201e04c3fSmrg b->func->end = w; 2237ec681f3Smrg if (b->func->start_block == NULL) { 2247ec681f3Smrg /* In this case, the function didn't have any actual blocks. It's 2257ec681f3Smrg * just a prototype so delete the function_impl. 2267ec681f3Smrg */ 2277ec681f3Smrg b->func->nir_func->impl = NULL; 2287ec681f3Smrg } 22901e04c3fSmrg b->func = NULL; 23001e04c3fSmrg break; 23101e04c3fSmrg 23201e04c3fSmrg case SpvOpFunctionParameter: { 2337ec681f3Smrg vtn_assert(b->func_param_idx < b->func->nir_func->num_params); 2347ec681f3Smrg struct vtn_type *type = vtn_get_type(b, w[1]); 2357ec681f3Smrg struct vtn_ssa_value *value = vtn_create_ssa_value(b, type->type); 2367ec681f3Smrg vtn_ssa_value_load_function_param(b, value, &b->func_param_idx); 2377ec681f3Smrg vtn_push_ssa_value(b, w[2], value); 23801e04c3fSmrg break; 23901e04c3fSmrg } 24001e04c3fSmrg 24101e04c3fSmrg case SpvOpLabel: { 24201e04c3fSmrg vtn_assert(b->block == NULL); 24301e04c3fSmrg b->block = rzalloc(b, struct vtn_block); 24401e04c3fSmrg b->block->node.type = vtn_cf_node_type_block; 24501e04c3fSmrg b->block->label = w; 24601e04c3fSmrg vtn_push_value(b, w[1], vtn_value_type_block)->block = b->block; 24701e04c3fSmrg 24801e04c3fSmrg if (b->func->start_block == NULL) { 24901e04c3fSmrg /* This is the first block encountered for this function. In this 25001e04c3fSmrg * case, we set the start block and add it to the list of 25101e04c3fSmrg * implemented functions that we'll walk later. 25201e04c3fSmrg */ 25301e04c3fSmrg b->func->start_block = b->block; 2547ec681f3Smrg list_addtail(&b->func->node.link, &b->functions); 25501e04c3fSmrg } 25601e04c3fSmrg break; 25701e04c3fSmrg } 25801e04c3fSmrg 25901e04c3fSmrg case SpvOpSelectionMerge: 26001e04c3fSmrg case SpvOpLoopMerge: 26101e04c3fSmrg vtn_assert(b->block && b->block->merge == NULL); 26201e04c3fSmrg b->block->merge = w; 26301e04c3fSmrg break; 26401e04c3fSmrg 26501e04c3fSmrg case SpvOpBranch: 26601e04c3fSmrg case SpvOpBranchConditional: 26701e04c3fSmrg case SpvOpSwitch: 26801e04c3fSmrg case SpvOpKill: 2697ec681f3Smrg case SpvOpTerminateInvocation: 2707ec681f3Smrg case SpvOpIgnoreIntersectionKHR: 2717ec681f3Smrg case SpvOpTerminateRayKHR: 27201e04c3fSmrg case SpvOpReturn: 27301e04c3fSmrg case SpvOpReturnValue: 27401e04c3fSmrg case SpvOpUnreachable: 27501e04c3fSmrg vtn_assert(b->block && b->block->branch == NULL); 27601e04c3fSmrg b->block->branch = w; 27701e04c3fSmrg b->block = NULL; 27801e04c3fSmrg break; 27901e04c3fSmrg 28001e04c3fSmrg default: 28101e04c3fSmrg /* Continue on as per normal */ 28201e04c3fSmrg return true; 28301e04c3fSmrg } 28401e04c3fSmrg 28501e04c3fSmrg return true; 28601e04c3fSmrg} 28701e04c3fSmrg 28801e04c3fSmrg/* This function performs a depth-first search of the cases and puts them 28901e04c3fSmrg * in fall-through order. 29001e04c3fSmrg */ 29101e04c3fSmrgstatic void 29201e04c3fSmrgvtn_order_case(struct vtn_switch *swtch, struct vtn_case *cse) 29301e04c3fSmrg{ 29401e04c3fSmrg if (cse->visited) 29501e04c3fSmrg return; 29601e04c3fSmrg 29701e04c3fSmrg cse->visited = true; 29801e04c3fSmrg 2997ec681f3Smrg list_del(&cse->node.link); 30001e04c3fSmrg 30101e04c3fSmrg if (cse->fallthrough) { 30201e04c3fSmrg vtn_order_case(swtch, cse->fallthrough); 30301e04c3fSmrg 30401e04c3fSmrg /* If we have a fall-through, place this case right before the case it 30501e04c3fSmrg * falls through to. This ensures that fallthroughs come one after 30601e04c3fSmrg * the other. These two can never get separated because that would 30701e04c3fSmrg * imply something else falling through to the same case. Also, this 30801e04c3fSmrg * can't break ordering because the DFS ensures that this case is 30901e04c3fSmrg * visited before anything that falls through to it. 31001e04c3fSmrg */ 3117ec681f3Smrg list_addtail(&cse->node.link, &cse->fallthrough->node.link); 31201e04c3fSmrg } else { 3137ec681f3Smrg list_add(&cse->node.link, &swtch->cases); 31401e04c3fSmrg } 31501e04c3fSmrg} 31601e04c3fSmrg 3177ec681f3Smrgstatic void 3187ec681f3Smrgvtn_switch_order_cases(struct vtn_switch *swtch) 31901e04c3fSmrg{ 3207ec681f3Smrg struct list_head cases; 3217ec681f3Smrg list_replace(&swtch->cases, &cases); 3227ec681f3Smrg list_inithead(&swtch->cases); 3237ec681f3Smrg while (!list_is_empty(&cases)) { 3247ec681f3Smrg struct vtn_case *cse = 3257ec681f3Smrg list_first_entry(&cases, struct vtn_case, node.link); 3267ec681f3Smrg vtn_order_case(swtch, cse); 32701e04c3fSmrg } 32801e04c3fSmrg} 32901e04c3fSmrg 33001e04c3fSmrgstatic void 3317ec681f3Smrgvtn_block_set_merge_cf_node(struct vtn_builder *b, struct vtn_block *block, 3327ec681f3Smrg struct vtn_cf_node *cf_node) 33301e04c3fSmrg{ 3347ec681f3Smrg vtn_fail_if(block->merge_cf_node != NULL, 3357ec681f3Smrg "The merge block declared by a header block cannot be a " 3367ec681f3Smrg "merge block declared by any other header block."); 33701e04c3fSmrg 3387ec681f3Smrg block->merge_cf_node = cf_node; 3397ec681f3Smrg} 34001e04c3fSmrg 3417ec681f3Smrg#define VTN_DECL_CF_NODE_FIND(_type) \ 3427ec681f3Smrgstatic inline struct vtn_##_type * \ 3437ec681f3Smrgvtn_cf_node_find_##_type(struct vtn_cf_node *node) \ 3447ec681f3Smrg{ \ 3457ec681f3Smrg while (node && node->type != vtn_cf_node_type_##_type) \ 3467ec681f3Smrg node = node->parent; \ 3477ec681f3Smrg return (struct vtn_##_type *)node; \ 3487ec681f3Smrg} 34901e04c3fSmrg 3507ec681f3SmrgVTN_DECL_CF_NODE_FIND(if) 3517ec681f3SmrgVTN_DECL_CF_NODE_FIND(loop) 3527ec681f3SmrgVTN_DECL_CF_NODE_FIND(case) 3537ec681f3SmrgVTN_DECL_CF_NODE_FIND(switch) 3547ec681f3SmrgVTN_DECL_CF_NODE_FIND(function) 35501e04c3fSmrg 3567ec681f3Smrgstatic enum vtn_branch_type 3577ec681f3Smrgvtn_handle_branch(struct vtn_builder *b, 3587ec681f3Smrg struct vtn_cf_node *cf_parent, 3597ec681f3Smrg struct vtn_block *target_block) 3607ec681f3Smrg{ 3617ec681f3Smrg struct vtn_loop *loop = vtn_cf_node_find_loop(cf_parent); 36201e04c3fSmrg 3637ec681f3Smrg /* Detect a loop back-edge first. That way none of the code below 3647ec681f3Smrg * accidentally operates on a loop back-edge. 3657ec681f3Smrg */ 3667ec681f3Smrg if (loop && target_block == loop->header_block) 3677ec681f3Smrg return vtn_branch_type_loop_back_edge; 3687ec681f3Smrg 3697ec681f3Smrg /* Try to detect fall-through */ 3707ec681f3Smrg if (target_block->switch_case) { 3717ec681f3Smrg /* When it comes to handling switch cases, we can break calls to 3727ec681f3Smrg * vtn_handle_branch into two cases: calls from within a case construct 3737ec681f3Smrg * and calls for the jump to each case construct. In the second case, 3747ec681f3Smrg * cf_parent is the vtn_switch itself and vtn_cf_node_find_case() will 3757ec681f3Smrg * return the outer switch case in which this switch is contained. It's 3767ec681f3Smrg * fine if the target block is a switch case from an outer switch as 3777ec681f3Smrg * long as it is also the switch break for this switch. 3787ec681f3Smrg */ 3797ec681f3Smrg struct vtn_case *switch_case = vtn_cf_node_find_case(cf_parent); 3807ec681f3Smrg 3817ec681f3Smrg /* This doesn't get called for the OpSwitch */ 3827ec681f3Smrg vtn_fail_if(switch_case == NULL, 3837ec681f3Smrg "A switch case can only be entered through an OpSwitch or " 3847ec681f3Smrg "falling through from another switch case."); 3857ec681f3Smrg 3867ec681f3Smrg /* Because block->switch_case is only set on the entry block for a given 3877ec681f3Smrg * switch case, we only ever get here if we're jumping to the start of a 3887ec681f3Smrg * switch case. It's possible, however, that a switch case could jump 3897ec681f3Smrg * to itself via a back-edge. That *should* get caught by the loop 3907ec681f3Smrg * handling case above but if we have a back edge without a loop merge, 3917ec681f3Smrg * we could en up here. 3927ec681f3Smrg */ 3937ec681f3Smrg vtn_fail_if(target_block->switch_case == switch_case, 3947ec681f3Smrg "A switch cannot fall-through to itself. Likely, there is " 3957ec681f3Smrg "a back-edge which is not to a loop header."); 39601e04c3fSmrg 3977ec681f3Smrg vtn_fail_if(target_block->switch_case->node.parent != 3987ec681f3Smrg switch_case->node.parent, 3997ec681f3Smrg "A switch case fall-through must come from the same " 4007ec681f3Smrg "OpSwitch construct"); 4017ec681f3Smrg 4027ec681f3Smrg vtn_fail_if(switch_case->fallthrough != NULL && 4037ec681f3Smrg switch_case->fallthrough != target_block->switch_case, 4047ec681f3Smrg "Each case construct can have at most one branch to " 4057ec681f3Smrg "another case construct"); 4067ec681f3Smrg 4077ec681f3Smrg switch_case->fallthrough = target_block->switch_case; 4087ec681f3Smrg 4097ec681f3Smrg /* We don't immediately return vtn_branch_type_switch_fallthrough 4107ec681f3Smrg * because it may also be a loop or switch break for an inner loop or 4117ec681f3Smrg * switch and that takes precedence. 4127ec681f3Smrg */ 4137ec681f3Smrg } 4147ec681f3Smrg 4157ec681f3Smrg if (loop && target_block == loop->cont_block) 4167ec681f3Smrg return vtn_branch_type_loop_continue; 4177ec681f3Smrg 4187ec681f3Smrg /* We walk blocks as a breadth-first search on the control-flow construct 4197ec681f3Smrg * tree where, when we find a construct, we add the vtn_cf_node for that 4207ec681f3Smrg * construct and continue iterating at the merge target block (if any). 4217ec681f3Smrg * Therefore, we want merges whose with parent == cf_parent to be treated 4227ec681f3Smrg * as regular branches. We only want to consider merges if they break out 4237ec681f3Smrg * of the current CF construct. 4247ec681f3Smrg */ 4257ec681f3Smrg if (target_block->merge_cf_node != NULL && 4267ec681f3Smrg target_block->merge_cf_node->parent != cf_parent) { 4277ec681f3Smrg switch (target_block->merge_cf_node->type) { 4287ec681f3Smrg case vtn_cf_node_type_if: 4297ec681f3Smrg for (struct vtn_cf_node *node = cf_parent; 4307ec681f3Smrg node != target_block->merge_cf_node; node = node->parent) { 4317ec681f3Smrg vtn_fail_if(node == NULL || node->type != vtn_cf_node_type_if, 4327ec681f3Smrg "Branching to the merge block of a selection " 4337ec681f3Smrg "construct can only be used to break out of a " 4347ec681f3Smrg "selection construct"); 4357ec681f3Smrg 4367ec681f3Smrg struct vtn_if *if_stmt = vtn_cf_node_as_if(node); 4377ec681f3Smrg 4387ec681f3Smrg /* This should be guaranteed by our iteration */ 4397ec681f3Smrg assert(if_stmt->merge_block != target_block); 4407ec681f3Smrg 4417ec681f3Smrg vtn_fail_if(if_stmt->merge_block != NULL, 4427ec681f3Smrg "Branching to the merge block of a selection " 4437ec681f3Smrg "construct can only be used to break out of the " 4447ec681f3Smrg "inner most nested selection level"); 4457ec681f3Smrg } 4467ec681f3Smrg return vtn_branch_type_if_merge; 4477ec681f3Smrg 4487ec681f3Smrg case vtn_cf_node_type_loop: 4497ec681f3Smrg vtn_fail_if(target_block->merge_cf_node != &loop->node, 4507ec681f3Smrg "Loop breaks can only break out of the inner most " 4517ec681f3Smrg "nested loop level"); 4527ec681f3Smrg return vtn_branch_type_loop_break; 4537ec681f3Smrg 4547ec681f3Smrg case vtn_cf_node_type_switch: { 4557ec681f3Smrg struct vtn_switch *swtch = vtn_cf_node_find_switch(cf_parent); 4567ec681f3Smrg vtn_fail_if(target_block->merge_cf_node != &swtch->node, 4577ec681f3Smrg "Switch breaks can only break out of the inner most " 4587ec681f3Smrg "nested switch level"); 4597ec681f3Smrg return vtn_branch_type_switch_break; 46001e04c3fSmrg } 46101e04c3fSmrg 4627ec681f3Smrg default: 4637ec681f3Smrg unreachable("Invalid CF node type for a merge"); 4647ec681f3Smrg } 4657ec681f3Smrg } 46601e04c3fSmrg 4677ec681f3Smrg if (target_block->switch_case) 4687ec681f3Smrg return vtn_branch_type_switch_fallthrough; 46901e04c3fSmrg 4707ec681f3Smrg return vtn_branch_type_none; 4717ec681f3Smrg} 47201e04c3fSmrg 4737ec681f3Smrgstruct vtn_cfg_work_item { 4747ec681f3Smrg struct list_head link; 47501e04c3fSmrg 4767ec681f3Smrg struct vtn_cf_node *cf_parent; 4777ec681f3Smrg struct list_head *cf_list; 4787ec681f3Smrg struct vtn_block *start_block; 4797ec681f3Smrg}; 48001e04c3fSmrg 4817ec681f3Smrgstatic void 4827ec681f3Smrgvtn_add_cfg_work_item(struct vtn_builder *b, 4837ec681f3Smrg struct list_head *work_list, 4847ec681f3Smrg struct vtn_cf_node *cf_parent, 4857ec681f3Smrg struct list_head *cf_list, 4867ec681f3Smrg struct vtn_block *start_block) 4877ec681f3Smrg{ 4887ec681f3Smrg struct vtn_cfg_work_item *work = ralloc(b, struct vtn_cfg_work_item); 4897ec681f3Smrg work->cf_parent = cf_parent; 4907ec681f3Smrg work->cf_list = cf_list; 4917ec681f3Smrg work->start_block = start_block; 4927ec681f3Smrg list_addtail(&work->link, work_list); 4937ec681f3Smrg} 49401e04c3fSmrg 4957ec681f3Smrg/* returns the default block */ 4967ec681f3Smrgstatic void 4977ec681f3Smrgvtn_parse_switch(struct vtn_builder *b, 4987ec681f3Smrg struct vtn_switch *swtch, 4997ec681f3Smrg const uint32_t *branch, 5007ec681f3Smrg struct list_head *case_list) 5017ec681f3Smrg{ 5027ec681f3Smrg const uint32_t *branch_end = branch + (branch[0] >> SpvWordCountShift); 5037ec681f3Smrg 5047ec681f3Smrg struct vtn_value *sel_val = vtn_untyped_value(b, branch[1]); 5057ec681f3Smrg vtn_fail_if(!sel_val->type || 5067ec681f3Smrg sel_val->type->base_type != vtn_base_type_scalar, 5077ec681f3Smrg "Selector of OpSwitch must have a type of OpTypeInt"); 5087ec681f3Smrg 5097ec681f3Smrg nir_alu_type sel_type = 5107ec681f3Smrg nir_get_nir_type_for_glsl_type(sel_val->type->type); 5117ec681f3Smrg vtn_fail_if(nir_alu_type_get_base_type(sel_type) != nir_type_int && 5127ec681f3Smrg nir_alu_type_get_base_type(sel_type) != nir_type_uint, 5137ec681f3Smrg "Selector of OpSwitch must have a type of OpTypeInt"); 5147ec681f3Smrg 5157ec681f3Smrg struct hash_table *block_to_case = _mesa_pointer_hash_table_create(b); 5167ec681f3Smrg 5177ec681f3Smrg bool is_default = true; 5187ec681f3Smrg const unsigned bitsize = nir_alu_type_get_type_size(sel_type); 5197ec681f3Smrg for (const uint32_t *w = branch + 2; w < branch_end;) { 5207ec681f3Smrg uint64_t literal = 0; 5217ec681f3Smrg if (!is_default) { 5227ec681f3Smrg if (bitsize <= 32) { 5237ec681f3Smrg literal = *(w++); 5247e102996Smaya } else { 5257ec681f3Smrg assert(bitsize == 64); 5267ec681f3Smrg literal = vtn_u64_literal(w); 5277ec681f3Smrg w += 2; 52801e04c3fSmrg } 5297ec681f3Smrg } 5307ec681f3Smrg struct vtn_block *case_block = vtn_block(b, *(w++)); 53101e04c3fSmrg 5327ec681f3Smrg struct hash_entry *case_entry = 5337ec681f3Smrg _mesa_hash_table_search(block_to_case, case_block); 53401e04c3fSmrg 5357ec681f3Smrg struct vtn_case *cse; 5367ec681f3Smrg if (case_entry) { 5377ec681f3Smrg cse = case_entry->data; 5387ec681f3Smrg } else { 5397ec681f3Smrg cse = rzalloc(b, struct vtn_case); 5407ec681f3Smrg 5417ec681f3Smrg cse->node.type = vtn_cf_node_type_case; 5427ec681f3Smrg cse->node.parent = swtch ? &swtch->node : NULL; 5437ec681f3Smrg cse->block = case_block; 5447ec681f3Smrg list_inithead(&cse->body); 5457ec681f3Smrg util_dynarray_init(&cse->values, b); 5467ec681f3Smrg 5477ec681f3Smrg list_addtail(&cse->node.link, case_list); 5487ec681f3Smrg _mesa_hash_table_insert(block_to_case, case_block, cse); 54901e04c3fSmrg } 55001e04c3fSmrg 5517ec681f3Smrg if (is_default) { 5527ec681f3Smrg cse->is_default = true; 5537ec681f3Smrg } else { 5547ec681f3Smrg util_dynarray_append(&cse->values, uint64_t, literal); 5557ec681f3Smrg } 55601e04c3fSmrg 5577ec681f3Smrg is_default = false; 5587ec681f3Smrg } 55901e04c3fSmrg 5607ec681f3Smrg _mesa_hash_table_destroy(block_to_case, NULL); 5617ec681f3Smrg} 56201e04c3fSmrg 5637ec681f3Smrg/* Processes a block and returns the next block to process or NULL if we've 5647ec681f3Smrg * reached the end of the construct. 5657ec681f3Smrg */ 5667ec681f3Smrgstatic struct vtn_block * 5677ec681f3Smrgvtn_process_block(struct vtn_builder *b, 5687ec681f3Smrg struct list_head *work_list, 5697ec681f3Smrg struct vtn_cf_node *cf_parent, 5707ec681f3Smrg struct list_head *cf_list, 5717ec681f3Smrg struct vtn_block *block) 5727ec681f3Smrg{ 5737ec681f3Smrg if (!list_is_empty(cf_list)) { 5747ec681f3Smrg /* vtn_process_block() acts like an iterator: it processes the given 5757ec681f3Smrg * block and then returns the next block to process. For a given 5767ec681f3Smrg * control-flow construct, vtn_build_cfg() calls vtn_process_block() 5777ec681f3Smrg * repeatedly until it finally returns NULL. Therefore, we know that 5787ec681f3Smrg * the only blocks on which vtn_process_block() can be called are either 5797ec681f3Smrg * the first block in a construct or a block that vtn_process_block() 5807ec681f3Smrg * returned for the current construct. If cf_list is empty then we know 5817ec681f3Smrg * that we're processing the first block in the construct and we have to 5827ec681f3Smrg * add it to the list. 5837ec681f3Smrg * 5847ec681f3Smrg * If cf_list is not empty, then it must be the block returned by the 5857ec681f3Smrg * previous call to vtn_process_block(). We know a priori that 5867ec681f3Smrg * vtn_process_block only returns either normal branches 5877ec681f3Smrg * (vtn_branch_type_none) or merge target blocks. 5887ec681f3Smrg */ 5897ec681f3Smrg switch (vtn_handle_branch(b, cf_parent, block)) { 5907ec681f3Smrg case vtn_branch_type_none: 5917ec681f3Smrg /* For normal branches, we want to process them and add them to the 5927ec681f3Smrg * current construct. Merge target blocks also look like normal 5937ec681f3Smrg * branches from the perspective of this construct. See also 5947ec681f3Smrg * vtn_handle_branch(). 59501e04c3fSmrg */ 5967ec681f3Smrg break; 59701e04c3fSmrg 5987ec681f3Smrg case vtn_branch_type_loop_continue: 5997ec681f3Smrg case vtn_branch_type_switch_fallthrough: 6007ec681f3Smrg /* The two cases where we can get early exits from a construct that 6017ec681f3Smrg * are not to that construct's merge target are loop continues and 6027ec681f3Smrg * switch fall-throughs. In these cases, we need to break out of the 6037ec681f3Smrg * current construct by returning NULL. 60401e04c3fSmrg */ 6057ec681f3Smrg return NULL; 60601e04c3fSmrg 6077ec681f3Smrg default: 6087ec681f3Smrg /* The only way we can get here is if something was used as two kinds 6097ec681f3Smrg * of merges at the same time and that's illegal. 6107ec681f3Smrg */ 6117ec681f3Smrg vtn_fail("A block was used as a merge target from two or more " 6127ec681f3Smrg "structured control-flow constructs"); 6137ec681f3Smrg } 6147ec681f3Smrg } 61501e04c3fSmrg 6167ec681f3Smrg /* Once a block has been processed, it is placed into and the list link 6177ec681f3Smrg * will point to something non-null. If we see a node we've already 6187ec681f3Smrg * processed here, it either exists in multiple functions or it's an 6197ec681f3Smrg * invalid back-edge. 6207ec681f3Smrg */ 6217ec681f3Smrg if (block->node.parent != NULL) { 6227ec681f3Smrg vtn_fail_if(vtn_cf_node_find_function(&block->node) != 6237ec681f3Smrg vtn_cf_node_find_function(cf_parent), 6247ec681f3Smrg "A block cannot exist in two functions at the " 6257ec681f3Smrg "same time"); 62601e04c3fSmrg 6277ec681f3Smrg vtn_fail("Invalid back or cross-edge in the CFG"); 6287ec681f3Smrg } 62901e04c3fSmrg 6307ec681f3Smrg if (block->merge && (*block->merge & SpvOpCodeMask) == SpvOpLoopMerge && 6317ec681f3Smrg block->loop == NULL) { 6327ec681f3Smrg vtn_fail_if((*block->branch & SpvOpCodeMask) != SpvOpBranch && 6337ec681f3Smrg (*block->branch & SpvOpCodeMask) != SpvOpBranchConditional, 6347ec681f3Smrg "An OpLoopMerge instruction must immediately precede " 6357ec681f3Smrg "either an OpBranch or OpBranchConditional instruction."); 6367ec681f3Smrg 6377ec681f3Smrg struct vtn_loop *loop = rzalloc(b, struct vtn_loop); 6387ec681f3Smrg 6397ec681f3Smrg loop->node.type = vtn_cf_node_type_loop; 6407ec681f3Smrg loop->node.parent = cf_parent; 6417ec681f3Smrg list_inithead(&loop->body); 6427ec681f3Smrg list_inithead(&loop->cont_body); 6437ec681f3Smrg loop->header_block = block; 6447ec681f3Smrg loop->break_block = vtn_block(b, block->merge[1]); 6457ec681f3Smrg loop->cont_block = vtn_block(b, block->merge[2]); 6467ec681f3Smrg loop->control = block->merge[3]; 6477ec681f3Smrg 6487ec681f3Smrg list_addtail(&loop->node.link, cf_list); 6497ec681f3Smrg block->loop = loop; 6507ec681f3Smrg 6517ec681f3Smrg /* Note: The work item for the main loop body will start with the 6527ec681f3Smrg * current block as its start block. If we weren't careful, we would 6537ec681f3Smrg * get here again and end up in an infinite loop. This is why we set 6547ec681f3Smrg * block->loop above and check for it before creating one. This way, 6557ec681f3Smrg * we only create the loop once and the second iteration that tries to 6567ec681f3Smrg * handle this loop goes to the cases below and gets handled as a 6577ec681f3Smrg * regular block. 6587ec681f3Smrg */ 6597ec681f3Smrg vtn_add_cfg_work_item(b, work_list, &loop->node, 6607ec681f3Smrg &loop->body, loop->header_block); 6617ec681f3Smrg 6627ec681f3Smrg /* For continue targets, SPIR-V guarantees the following: 6637ec681f3Smrg * 6647ec681f3Smrg * - the Continue Target must dominate the back-edge block 6657ec681f3Smrg * - the back-edge block must post dominate the Continue Target 6667ec681f3Smrg * 6677ec681f3Smrg * If the header block is the same as the continue target, this 6687ec681f3Smrg * condition is trivially satisfied and there is no real continue 6697ec681f3Smrg * section. 6707ec681f3Smrg */ 6717ec681f3Smrg if (loop->cont_block != loop->header_block) { 6727ec681f3Smrg vtn_add_cfg_work_item(b, work_list, &loop->node, 6737ec681f3Smrg &loop->cont_body, loop->cont_block); 6747ec681f3Smrg } 67501e04c3fSmrg 6767ec681f3Smrg vtn_block_set_merge_cf_node(b, loop->break_block, &loop->node); 6777ec681f3Smrg 6787ec681f3Smrg return loop->break_block; 6797ec681f3Smrg } 6807ec681f3Smrg 6817ec681f3Smrg /* Add the block to the CF list */ 6827ec681f3Smrg block->node.parent = cf_parent; 6837ec681f3Smrg list_addtail(&block->node.link, cf_list); 6847ec681f3Smrg 6857ec681f3Smrg switch (*block->branch & SpvOpCodeMask) { 6867ec681f3Smrg case SpvOpBranch: { 6877ec681f3Smrg struct vtn_block *branch_block = vtn_block(b, block->branch[1]); 6887ec681f3Smrg 6897ec681f3Smrg block->branch_type = vtn_handle_branch(b, cf_parent, branch_block); 6907ec681f3Smrg 6917ec681f3Smrg if (block->branch_type == vtn_branch_type_none) 6927ec681f3Smrg return branch_block; 6937ec681f3Smrg else 6947ec681f3Smrg return NULL; 6957ec681f3Smrg } 6967ec681f3Smrg 6977ec681f3Smrg case SpvOpReturn: 6987ec681f3Smrg case SpvOpReturnValue: 6997ec681f3Smrg block->branch_type = vtn_branch_type_return; 7007ec681f3Smrg return NULL; 7017ec681f3Smrg 7027ec681f3Smrg case SpvOpKill: 7037ec681f3Smrg block->branch_type = vtn_branch_type_discard; 7047ec681f3Smrg return NULL; 7057ec681f3Smrg 7067ec681f3Smrg case SpvOpTerminateInvocation: 7077ec681f3Smrg block->branch_type = vtn_branch_type_terminate_invocation; 7087ec681f3Smrg return NULL; 7097ec681f3Smrg 7107ec681f3Smrg case SpvOpIgnoreIntersectionKHR: 7117ec681f3Smrg block->branch_type = vtn_branch_type_ignore_intersection; 7127ec681f3Smrg return NULL; 7137ec681f3Smrg 7147ec681f3Smrg case SpvOpTerminateRayKHR: 7157ec681f3Smrg block->branch_type = vtn_branch_type_terminate_ray; 7167ec681f3Smrg return NULL; 7177ec681f3Smrg 7187ec681f3Smrg case SpvOpBranchConditional: { 7197ec681f3Smrg struct vtn_value *cond_val = vtn_untyped_value(b, block->branch[1]); 7207ec681f3Smrg vtn_fail_if(!cond_val->type || 7217ec681f3Smrg cond_val->type->base_type != vtn_base_type_scalar || 7227ec681f3Smrg cond_val->type->type != glsl_bool_type(), 7237ec681f3Smrg "Condition must be a Boolean type scalar"); 7247ec681f3Smrg 7257ec681f3Smrg struct vtn_if *if_stmt = rzalloc(b, struct vtn_if); 7267ec681f3Smrg 7277ec681f3Smrg if_stmt->node.type = vtn_cf_node_type_if; 7287ec681f3Smrg if_stmt->node.parent = cf_parent; 7297ec681f3Smrg if_stmt->header_block = block; 7307ec681f3Smrg list_inithead(&if_stmt->then_body); 7317ec681f3Smrg list_inithead(&if_stmt->else_body); 7327ec681f3Smrg 7337ec681f3Smrg list_addtail(&if_stmt->node.link, cf_list); 7347ec681f3Smrg 7357ec681f3Smrg if (block->merge && 7367ec681f3Smrg (*block->merge & SpvOpCodeMask) == SpvOpSelectionMerge) { 7377ec681f3Smrg /* We may not always have a merge block and that merge doesn't 7387ec681f3Smrg * technically have to be an OpSelectionMerge. We could have a block 7397ec681f3Smrg * with an OpLoopMerge which ends in an OpBranchConditional. 7407ec681f3Smrg */ 7417ec681f3Smrg if_stmt->merge_block = vtn_block(b, block->merge[1]); 7427ec681f3Smrg vtn_block_set_merge_cf_node(b, if_stmt->merge_block, &if_stmt->node); 7437ec681f3Smrg 7447ec681f3Smrg if_stmt->control = block->merge[2]; 7457ec681f3Smrg } 7467ec681f3Smrg 7477ec681f3Smrg struct vtn_block *then_block = vtn_block(b, block->branch[2]); 7487ec681f3Smrg if_stmt->then_type = vtn_handle_branch(b, &if_stmt->node, then_block); 7497ec681f3Smrg if (if_stmt->then_type == vtn_branch_type_none) { 7507ec681f3Smrg vtn_add_cfg_work_item(b, work_list, &if_stmt->node, 7517ec681f3Smrg &if_stmt->then_body, then_block); 7527ec681f3Smrg } 7537ec681f3Smrg 7547ec681f3Smrg struct vtn_block *else_block = vtn_block(b, block->branch[3]); 7557ec681f3Smrg if (then_block != else_block) { 7567ec681f3Smrg if_stmt->else_type = vtn_handle_branch(b, &if_stmt->node, else_block); 7577ec681f3Smrg if (if_stmt->else_type == vtn_branch_type_none) { 7587ec681f3Smrg vtn_add_cfg_work_item(b, work_list, &if_stmt->node, 7597ec681f3Smrg &if_stmt->else_body, else_block); 76001e04c3fSmrg } 7617ec681f3Smrg } 76201e04c3fSmrg 7637ec681f3Smrg return if_stmt->merge_block; 7647ec681f3Smrg } 7657ec681f3Smrg 7667ec681f3Smrg case SpvOpSwitch: { 7677ec681f3Smrg struct vtn_switch *swtch = rzalloc(b, struct vtn_switch); 7687ec681f3Smrg 7697ec681f3Smrg swtch->node.type = vtn_cf_node_type_switch; 7707ec681f3Smrg swtch->node.parent = cf_parent; 7717ec681f3Smrg swtch->selector = block->branch[1]; 7727ec681f3Smrg list_inithead(&swtch->cases); 7737ec681f3Smrg 7747ec681f3Smrg list_addtail(&swtch->node.link, cf_list); 7757ec681f3Smrg 7767ec681f3Smrg /* We may not always have a merge block */ 7777ec681f3Smrg if (block->merge) { 7787ec681f3Smrg vtn_fail_if((*block->merge & SpvOpCodeMask) != SpvOpSelectionMerge, 7797ec681f3Smrg "An OpLoopMerge instruction must immediately precede " 7807ec681f3Smrg "either an OpBranch or OpBranchConditional " 7817ec681f3Smrg "instruction."); 7827ec681f3Smrg swtch->break_block = vtn_block(b, block->merge[1]); 7837ec681f3Smrg vtn_block_set_merge_cf_node(b, swtch->break_block, &swtch->node); 78401e04c3fSmrg } 78501e04c3fSmrg 7867ec681f3Smrg /* First, we go through and record all of the cases. */ 7877ec681f3Smrg vtn_parse_switch(b, swtch, block->branch, &swtch->cases); 7887ec681f3Smrg 7897ec681f3Smrg /* Gather the branch types for the switch */ 7907ec681f3Smrg vtn_foreach_cf_node(case_node, &swtch->cases) { 7917ec681f3Smrg struct vtn_case *cse = vtn_cf_node_as_case(case_node); 7927ec681f3Smrg 7937ec681f3Smrg cse->type = vtn_handle_branch(b, &swtch->node, cse->block); 7947ec681f3Smrg switch (cse->type) { 7957ec681f3Smrg case vtn_branch_type_none: 7967ec681f3Smrg /* This is a "real" cases which has stuff in it */ 7977ec681f3Smrg vtn_fail_if(cse->block->switch_case != NULL, 7987ec681f3Smrg "OpSwitch has a case which is also in another " 7997ec681f3Smrg "OpSwitch construct"); 8007ec681f3Smrg cse->block->switch_case = cse; 8017ec681f3Smrg vtn_add_cfg_work_item(b, work_list, &cse->node, 8027ec681f3Smrg &cse->body, cse->block); 8037ec681f3Smrg break; 8047ec681f3Smrg 8057ec681f3Smrg case vtn_branch_type_switch_break: 8067ec681f3Smrg case vtn_branch_type_loop_break: 8077ec681f3Smrg case vtn_branch_type_loop_continue: 8087ec681f3Smrg /* Switch breaks as well as loop breaks and continues can be 8097ec681f3Smrg * used to break out of a switch construct or as direct targets 8107ec681f3Smrg * of the OpSwitch. 8117ec681f3Smrg */ 8127ec681f3Smrg break; 81301e04c3fSmrg 8147ec681f3Smrg default: 8157ec681f3Smrg vtn_fail("Target of OpSwitch is not a valid structured exit " 8167ec681f3Smrg "from the switch construct."); 8177ec681f3Smrg } 81801e04c3fSmrg } 8197ec681f3Smrg 8207ec681f3Smrg return swtch->break_block; 8217ec681f3Smrg } 8227ec681f3Smrg 8237ec681f3Smrg case SpvOpUnreachable: 8247ec681f3Smrg return NULL; 8257ec681f3Smrg 8267ec681f3Smrg default: 8277ec681f3Smrg vtn_fail("Block did not end with a valid branch instruction"); 82801e04c3fSmrg } 82901e04c3fSmrg} 83001e04c3fSmrg 83101e04c3fSmrgvoid 83201e04c3fSmrgvtn_build_cfg(struct vtn_builder *b, const uint32_t *words, const uint32_t *end) 83301e04c3fSmrg{ 83401e04c3fSmrg vtn_foreach_instruction(b, words, end, 83501e04c3fSmrg vtn_cfg_handle_prepass_instruction); 83601e04c3fSmrg 8377ec681f3Smrg if (b->shader->info.stage == MESA_SHADER_KERNEL) 8387ec681f3Smrg return; 8397ec681f3Smrg 8407ec681f3Smrg vtn_foreach_cf_node(func_node, &b->functions) { 8417ec681f3Smrg struct vtn_function *func = vtn_cf_node_as_function(func_node); 8427ec681f3Smrg 8437ec681f3Smrg /* We build the CFG for each function by doing a breadth-first search on 8447ec681f3Smrg * the control-flow graph. We keep track of our state using a worklist. 8457ec681f3Smrg * Doing a BFS ensures that we visit each structured control-flow 8467ec681f3Smrg * construct and its merge node before we visit the stuff inside the 8477ec681f3Smrg * construct. 8487ec681f3Smrg */ 8497ec681f3Smrg struct list_head work_list; 8507ec681f3Smrg list_inithead(&work_list); 8517ec681f3Smrg vtn_add_cfg_work_item(b, &work_list, &func->node, &func->body, 8527ec681f3Smrg func->start_block); 8537ec681f3Smrg 8547ec681f3Smrg while (!list_is_empty(&work_list)) { 8557ec681f3Smrg struct vtn_cfg_work_item *work = 8567ec681f3Smrg list_first_entry(&work_list, struct vtn_cfg_work_item, link); 8577ec681f3Smrg list_del(&work->link); 8587ec681f3Smrg 8597ec681f3Smrg for (struct vtn_block *block = work->start_block; block; ) { 8607ec681f3Smrg block = vtn_process_block(b, &work_list, work->cf_parent, 8617ec681f3Smrg work->cf_list, block); 8627ec681f3Smrg } 8637ec681f3Smrg } 86401e04c3fSmrg } 86501e04c3fSmrg} 86601e04c3fSmrg 86701e04c3fSmrgstatic bool 86801e04c3fSmrgvtn_handle_phis_first_pass(struct vtn_builder *b, SpvOp opcode, 86901e04c3fSmrg const uint32_t *w, unsigned count) 87001e04c3fSmrg{ 87101e04c3fSmrg if (opcode == SpvOpLabel) 87201e04c3fSmrg return true; /* Nothing to do */ 87301e04c3fSmrg 87401e04c3fSmrg /* If this isn't a phi node, stop. */ 87501e04c3fSmrg if (opcode != SpvOpPhi) 87601e04c3fSmrg return false; 87701e04c3fSmrg 87801e04c3fSmrg /* For handling phi nodes, we do a poor-man's out-of-ssa on the spot. 87901e04c3fSmrg * For each phi, we create a variable with the appropreate type and 88001e04c3fSmrg * do a load from that variable. Then, in a second pass, we add 88101e04c3fSmrg * stores to that variable to each of the predecessor blocks. 88201e04c3fSmrg * 88301e04c3fSmrg * We could do something more intelligent here. However, in order to 88401e04c3fSmrg * handle loops and things properly, we really need dominance 88501e04c3fSmrg * information. It would end up basically being the into-SSA 88601e04c3fSmrg * algorithm all over again. It's easier if we just let 88701e04c3fSmrg * lower_vars_to_ssa do that for us instead of repeating it here. 88801e04c3fSmrg */ 8897ec681f3Smrg struct vtn_type *type = vtn_get_type(b, w[1]); 89001e04c3fSmrg nir_variable *phi_var = 89101e04c3fSmrg nir_local_variable_create(b->nb.impl, type->type, "phi"); 89201e04c3fSmrg _mesa_hash_table_insert(b->phi_table, w, phi_var); 89301e04c3fSmrg 8947ec681f3Smrg vtn_push_ssa_value(b, w[2], 8957ec681f3Smrg vtn_local_load(b, nir_build_deref_var(&b->nb, phi_var), 0)); 89601e04c3fSmrg 89701e04c3fSmrg return true; 89801e04c3fSmrg} 89901e04c3fSmrg 90001e04c3fSmrgstatic bool 90101e04c3fSmrgvtn_handle_phi_second_pass(struct vtn_builder *b, SpvOp opcode, 90201e04c3fSmrg const uint32_t *w, unsigned count) 90301e04c3fSmrg{ 90401e04c3fSmrg if (opcode != SpvOpPhi) 90501e04c3fSmrg return true; 90601e04c3fSmrg 90701e04c3fSmrg struct hash_entry *phi_entry = _mesa_hash_table_search(b->phi_table, w); 9087ec681f3Smrg 9097ec681f3Smrg /* It's possible that this phi is in an unreachable block in which case it 9107ec681f3Smrg * may never have been emitted and therefore may not be in the hash table. 9117ec681f3Smrg * In this case, there's no var for it and it's safe to just bail. 9127ec681f3Smrg */ 9137ec681f3Smrg if (phi_entry == NULL) 9147ec681f3Smrg return true; 9157ec681f3Smrg 91601e04c3fSmrg nir_variable *phi_var = phi_entry->data; 91701e04c3fSmrg 91801e04c3fSmrg for (unsigned i = 3; i < count; i += 2) { 9197ec681f3Smrg struct vtn_block *pred = vtn_block(b, w[i + 1]); 9207ec681f3Smrg 9217ec681f3Smrg /* If block does not have end_nop, that is because it is an unreacheable 9227ec681f3Smrg * block, and hence it is not worth to handle it */ 9237ec681f3Smrg if (!pred->end_nop) 9247ec681f3Smrg continue; 92501e04c3fSmrg 92601e04c3fSmrg b->nb.cursor = nir_after_instr(&pred->end_nop->instr); 92701e04c3fSmrg 92801e04c3fSmrg struct vtn_ssa_value *src = vtn_ssa_value(b, w[i]); 92901e04c3fSmrg 9307e102996Smaya vtn_local_store(b, src, nir_build_deref_var(&b->nb, phi_var), 0); 93101e04c3fSmrg } 93201e04c3fSmrg 93301e04c3fSmrg return true; 93401e04c3fSmrg} 93501e04c3fSmrg 93601e04c3fSmrgstatic void 93701e04c3fSmrgvtn_emit_branch(struct vtn_builder *b, enum vtn_branch_type branch_type, 93801e04c3fSmrg nir_variable *switch_fall_var, bool *has_switch_break) 93901e04c3fSmrg{ 94001e04c3fSmrg switch (branch_type) { 9417ec681f3Smrg case vtn_branch_type_if_merge: 9427ec681f3Smrg break; /* Nothing to do */ 94301e04c3fSmrg case vtn_branch_type_switch_break: 94401e04c3fSmrg nir_store_var(&b->nb, switch_fall_var, nir_imm_false(&b->nb), 1); 94501e04c3fSmrg *has_switch_break = true; 94601e04c3fSmrg break; 94701e04c3fSmrg case vtn_branch_type_switch_fallthrough: 94801e04c3fSmrg break; /* Nothing to do */ 94901e04c3fSmrg case vtn_branch_type_loop_break: 95001e04c3fSmrg nir_jump(&b->nb, nir_jump_break); 95101e04c3fSmrg break; 95201e04c3fSmrg case vtn_branch_type_loop_continue: 95301e04c3fSmrg nir_jump(&b->nb, nir_jump_continue); 95401e04c3fSmrg break; 9557ec681f3Smrg case vtn_branch_type_loop_back_edge: 9567ec681f3Smrg break; 95701e04c3fSmrg case vtn_branch_type_return: 95801e04c3fSmrg nir_jump(&b->nb, nir_jump_return); 95901e04c3fSmrg break; 9607ec681f3Smrg case vtn_branch_type_discard: 9617ec681f3Smrg if (b->convert_discard_to_demote) 9627ec681f3Smrg nir_demote(&b->nb); 9637ec681f3Smrg else 9647ec681f3Smrg nir_discard(&b->nb); 9657ec681f3Smrg break; 9667ec681f3Smrg case vtn_branch_type_terminate_invocation: 9677ec681f3Smrg nir_terminate(&b->nb); 9687ec681f3Smrg break; 9697ec681f3Smrg case vtn_branch_type_ignore_intersection: 9707ec681f3Smrg nir_ignore_ray_intersection(&b->nb); 9717ec681f3Smrg nir_jump(&b->nb, nir_jump_halt); 9727ec681f3Smrg break; 9737ec681f3Smrg case vtn_branch_type_terminate_ray: 9747ec681f3Smrg nir_terminate_ray(&b->nb); 9757ec681f3Smrg nir_jump(&b->nb, nir_jump_halt); 97601e04c3fSmrg break; 97701e04c3fSmrg default: 97801e04c3fSmrg vtn_fail("Invalid branch type"); 97901e04c3fSmrg } 98001e04c3fSmrg} 98101e04c3fSmrg 9827e102996Smayastatic nir_ssa_def * 9837e102996Smayavtn_switch_case_condition(struct vtn_builder *b, struct vtn_switch *swtch, 9847e102996Smaya nir_ssa_def *sel, struct vtn_case *cse) 9857e102996Smaya{ 9867e102996Smaya if (cse->is_default) { 9877e102996Smaya nir_ssa_def *any = nir_imm_false(&b->nb); 9887ec681f3Smrg vtn_foreach_cf_node(other_node, &swtch->cases) { 9897ec681f3Smrg struct vtn_case *other = vtn_cf_node_as_case(other_node); 9907e102996Smaya if (other->is_default) 9917e102996Smaya continue; 9927e102996Smaya 9937e102996Smaya any = nir_ior(&b->nb, any, 9947e102996Smaya vtn_switch_case_condition(b, swtch, sel, other)); 9957e102996Smaya } 9967e102996Smaya return nir_inot(&b->nb, any); 9977e102996Smaya } else { 9987e102996Smaya nir_ssa_def *cond = nir_imm_false(&b->nb); 9997ec681f3Smrg util_dynarray_foreach(&cse->values, uint64_t, val) 10007ec681f3Smrg cond = nir_ior(&b->nb, cond, nir_ieq_imm(&b->nb, sel, *val)); 10017e102996Smaya return cond; 10027e102996Smaya } 10037e102996Smaya} 10047e102996Smaya 10057e102996Smayastatic nir_loop_control 10067e102996Smayavtn_loop_control(struct vtn_builder *b, struct vtn_loop *vtn_loop) 10077e102996Smaya{ 10087e102996Smaya if (vtn_loop->control == SpvLoopControlMaskNone) 10097e102996Smaya return nir_loop_control_none; 10107e102996Smaya else if (vtn_loop->control & SpvLoopControlDontUnrollMask) 10117e102996Smaya return nir_loop_control_dont_unroll; 10127e102996Smaya else if (vtn_loop->control & SpvLoopControlUnrollMask) 10137e102996Smaya return nir_loop_control_unroll; 10147e102996Smaya else if (vtn_loop->control & SpvLoopControlDependencyInfiniteMask || 10157ec681f3Smrg vtn_loop->control & SpvLoopControlDependencyLengthMask || 10167ec681f3Smrg vtn_loop->control & SpvLoopControlMinIterationsMask || 10177ec681f3Smrg vtn_loop->control & SpvLoopControlMaxIterationsMask || 10187ec681f3Smrg vtn_loop->control & SpvLoopControlIterationMultipleMask || 10197ec681f3Smrg vtn_loop->control & SpvLoopControlPeelCountMask || 10207ec681f3Smrg vtn_loop->control & SpvLoopControlPartialCountMask) { 10217e102996Smaya /* We do not do anything special with these yet. */ 10227e102996Smaya return nir_loop_control_none; 10237e102996Smaya } else { 10247e102996Smaya vtn_fail("Invalid loop control"); 10257e102996Smaya } 10267e102996Smaya} 10277e102996Smaya 10287e102996Smayastatic nir_selection_control 10297e102996Smayavtn_selection_control(struct vtn_builder *b, struct vtn_if *vtn_if) 10307e102996Smaya{ 10317e102996Smaya if (vtn_if->control == SpvSelectionControlMaskNone) 10327e102996Smaya return nir_selection_control_none; 10337e102996Smaya else if (vtn_if->control & SpvSelectionControlDontFlattenMask) 10347e102996Smaya return nir_selection_control_dont_flatten; 10357e102996Smaya else if (vtn_if->control & SpvSelectionControlFlattenMask) 10367e102996Smaya return nir_selection_control_flatten; 10377e102996Smaya else 10387e102996Smaya vtn_fail("Invalid selection control"); 10397e102996Smaya} 10407e102996Smaya 104101e04c3fSmrgstatic void 10427ec681f3Smrgvtn_emit_ret_store(struct vtn_builder *b, struct vtn_block *block) 10437ec681f3Smrg{ 10447ec681f3Smrg if ((*block->branch & SpvOpCodeMask) != SpvOpReturnValue) 10457ec681f3Smrg return; 10467ec681f3Smrg 10477ec681f3Smrg vtn_fail_if(b->func->type->return_type->base_type == vtn_base_type_void, 10487ec681f3Smrg "Return with a value from a function returning void"); 10497ec681f3Smrg struct vtn_ssa_value *src = vtn_ssa_value(b, block->branch[1]); 10507ec681f3Smrg const struct glsl_type *ret_type = 10517ec681f3Smrg glsl_get_bare_type(b->func->type->return_type->type); 10527ec681f3Smrg nir_deref_instr *ret_deref = 10537ec681f3Smrg nir_build_deref_cast(&b->nb, nir_load_param(&b->nb, 0), 10547ec681f3Smrg nir_var_function_temp, ret_type, 0); 10557ec681f3Smrg vtn_local_store(b, src, ret_deref, 0); 10567ec681f3Smrg} 10577ec681f3Smrg 10587ec681f3Smrgstatic void 10597ec681f3Smrgvtn_emit_cf_list_structured(struct vtn_builder *b, struct list_head *cf_list, 10607ec681f3Smrg nir_variable *switch_fall_var, 10617ec681f3Smrg bool *has_switch_break, 10627ec681f3Smrg vtn_instruction_handler handler) 106301e04c3fSmrg{ 10647ec681f3Smrg vtn_foreach_cf_node(node, cf_list) { 106501e04c3fSmrg switch (node->type) { 106601e04c3fSmrg case vtn_cf_node_type_block: { 10677ec681f3Smrg struct vtn_block *block = vtn_cf_node_as_block(node); 106801e04c3fSmrg 106901e04c3fSmrg const uint32_t *block_start = block->label; 107001e04c3fSmrg const uint32_t *block_end = block->merge ? block->merge : 107101e04c3fSmrg block->branch; 107201e04c3fSmrg 107301e04c3fSmrg block_start = vtn_foreach_instruction(b, block_start, block_end, 107401e04c3fSmrg vtn_handle_phis_first_pass); 107501e04c3fSmrg 107601e04c3fSmrg vtn_foreach_instruction(b, block_start, block_end, handler); 107701e04c3fSmrg 10787ec681f3Smrg block->end_nop = nir_nop(&b->nb); 10797ec681f3Smrg 10807ec681f3Smrg vtn_emit_ret_store(b, block); 108101e04c3fSmrg 108201e04c3fSmrg if (block->branch_type != vtn_branch_type_none) { 108301e04c3fSmrg vtn_emit_branch(b, block->branch_type, 108401e04c3fSmrg switch_fall_var, has_switch_break); 10857e102996Smaya return; 108601e04c3fSmrg } 108701e04c3fSmrg 108801e04c3fSmrg break; 108901e04c3fSmrg } 109001e04c3fSmrg 109101e04c3fSmrg case vtn_cf_node_type_if: { 10927ec681f3Smrg struct vtn_if *vtn_if = vtn_cf_node_as_if(node); 10937ec681f3Smrg const uint32_t *branch = vtn_if->header_block->branch; 10947ec681f3Smrg vtn_assert((branch[0] & SpvOpCodeMask) == SpvOpBranchConditional); 10957ec681f3Smrg 10967ec681f3Smrg /* If both branches are the same, just emit the first block, which is 10977ec681f3Smrg * the only one we filled when building the CFG. 10987ec681f3Smrg */ 10997ec681f3Smrg if (branch[2] == branch[3]) { 11007ec681f3Smrg vtn_emit_cf_list_structured(b, &vtn_if->then_body, 11017ec681f3Smrg switch_fall_var, has_switch_break, handler); 11027ec681f3Smrg break; 11037ec681f3Smrg } 11047ec681f3Smrg 110501e04c3fSmrg bool sw_break = false; 110601e04c3fSmrg 110701e04c3fSmrg nir_if *nif = 11087ec681f3Smrg nir_push_if(&b->nb, vtn_get_nir_ssa(b, branch[1])); 11097e102996Smaya 11107e102996Smaya nif->control = vtn_selection_control(b, vtn_if); 11117e102996Smaya 111201e04c3fSmrg if (vtn_if->then_type == vtn_branch_type_none) { 11137ec681f3Smrg vtn_emit_cf_list_structured(b, &vtn_if->then_body, 11147ec681f3Smrg switch_fall_var, &sw_break, handler); 111501e04c3fSmrg } else { 111601e04c3fSmrg vtn_emit_branch(b, vtn_if->then_type, switch_fall_var, &sw_break); 111701e04c3fSmrg } 111801e04c3fSmrg 111901e04c3fSmrg nir_push_else(&b->nb, nif); 112001e04c3fSmrg if (vtn_if->else_type == vtn_branch_type_none) { 11217ec681f3Smrg vtn_emit_cf_list_structured(b, &vtn_if->else_body, 11227ec681f3Smrg switch_fall_var, &sw_break, handler); 112301e04c3fSmrg } else { 112401e04c3fSmrg vtn_emit_branch(b, vtn_if->else_type, switch_fall_var, &sw_break); 112501e04c3fSmrg } 112601e04c3fSmrg 112701e04c3fSmrg nir_pop_if(&b->nb, nif); 112801e04c3fSmrg 112901e04c3fSmrg /* If we encountered a switch break somewhere inside of the if, 113001e04c3fSmrg * then it would have been handled correctly by calling 113101e04c3fSmrg * emit_cf_list or emit_branch for the interrior. However, we 113201e04c3fSmrg * need to predicate everything following on wether or not we're 113301e04c3fSmrg * still going. 113401e04c3fSmrg */ 113501e04c3fSmrg if (sw_break) { 113601e04c3fSmrg *has_switch_break = true; 113701e04c3fSmrg nir_push_if(&b->nb, nir_load_var(&b->nb, switch_fall_var)); 113801e04c3fSmrg } 113901e04c3fSmrg break; 114001e04c3fSmrg } 114101e04c3fSmrg 114201e04c3fSmrg case vtn_cf_node_type_loop: { 11437ec681f3Smrg struct vtn_loop *vtn_loop = vtn_cf_node_as_loop(node); 114401e04c3fSmrg 114501e04c3fSmrg nir_loop *loop = nir_push_loop(&b->nb); 11467e102996Smaya loop->control = vtn_loop_control(b, vtn_loop); 11477e102996Smaya 11487ec681f3Smrg vtn_emit_cf_list_structured(b, &vtn_loop->body, NULL, NULL, handler); 114901e04c3fSmrg 11507ec681f3Smrg if (!list_is_empty(&vtn_loop->cont_body)) { 115101e04c3fSmrg /* If we have a non-trivial continue body then we need to put 115201e04c3fSmrg * it at the beginning of the loop with a flag to ensure that 115301e04c3fSmrg * it doesn't get executed in the first iteration. 115401e04c3fSmrg */ 115501e04c3fSmrg nir_variable *do_cont = 115601e04c3fSmrg nir_local_variable_create(b->nb.impl, glsl_bool_type(), "cont"); 115701e04c3fSmrg 115801e04c3fSmrg b->nb.cursor = nir_before_cf_node(&loop->cf_node); 115901e04c3fSmrg nir_store_var(&b->nb, do_cont, nir_imm_false(&b->nb), 1); 116001e04c3fSmrg 116101e04c3fSmrg b->nb.cursor = nir_before_cf_list(&loop->body); 116201e04c3fSmrg 116301e04c3fSmrg nir_if *cont_if = 116401e04c3fSmrg nir_push_if(&b->nb, nir_load_var(&b->nb, do_cont)); 116501e04c3fSmrg 11667ec681f3Smrg vtn_emit_cf_list_structured(b, &vtn_loop->cont_body, NULL, NULL, 11677ec681f3Smrg handler); 116801e04c3fSmrg 116901e04c3fSmrg nir_pop_if(&b->nb, cont_if); 117001e04c3fSmrg 117101e04c3fSmrg nir_store_var(&b->nb, do_cont, nir_imm_true(&b->nb), 1); 117201e04c3fSmrg } 117301e04c3fSmrg 117401e04c3fSmrg nir_pop_loop(&b->nb, loop); 117501e04c3fSmrg break; 117601e04c3fSmrg } 117701e04c3fSmrg 117801e04c3fSmrg case vtn_cf_node_type_switch: { 11797ec681f3Smrg struct vtn_switch *vtn_switch = vtn_cf_node_as_switch(node); 11807ec681f3Smrg 11817ec681f3Smrg /* Before we can emit anything, we need to sort the list of cases in 11827ec681f3Smrg * fall-through order. 11837ec681f3Smrg */ 11847ec681f3Smrg vtn_switch_order_cases(vtn_switch); 118501e04c3fSmrg 118601e04c3fSmrg /* First, we create a variable to keep track of whether or not the 118701e04c3fSmrg * switch is still going at any given point. Any switch breaks 118801e04c3fSmrg * will set this variable to false. 118901e04c3fSmrg */ 119001e04c3fSmrg nir_variable *fall_var = 119101e04c3fSmrg nir_local_variable_create(b->nb.impl, glsl_bool_type(), "fall"); 119201e04c3fSmrg nir_store_var(&b->nb, fall_var, nir_imm_false(&b->nb), 1); 119301e04c3fSmrg 11947ec681f3Smrg nir_ssa_def *sel = vtn_get_nir_ssa(b, vtn_switch->selector); 119501e04c3fSmrg 119601e04c3fSmrg /* Now we can walk the list of cases and actually emit code */ 11977ec681f3Smrg vtn_foreach_cf_node(case_node, &vtn_switch->cases) { 11987ec681f3Smrg struct vtn_case *cse = vtn_cf_node_as_case(case_node); 11997ec681f3Smrg 12007ec681f3Smrg /* If this case jumps directly to the break block, we don't have 12017ec681f3Smrg * to handle the case as the body is empty and doesn't fall 12027ec681f3Smrg * through. 12037ec681f3Smrg */ 12047ec681f3Smrg if (cse->block == vtn_switch->break_block) 12057ec681f3Smrg continue; 12067ec681f3Smrg 120701e04c3fSmrg /* Figure out the condition */ 12087e102996Smaya nir_ssa_def *cond = 12097e102996Smaya vtn_switch_case_condition(b, vtn_switch, sel, cse); 121001e04c3fSmrg /* Take fallthrough into account */ 121101e04c3fSmrg cond = nir_ior(&b->nb, cond, nir_load_var(&b->nb, fall_var)); 121201e04c3fSmrg 121301e04c3fSmrg nir_if *case_if = nir_push_if(&b->nb, cond); 121401e04c3fSmrg 121501e04c3fSmrg bool has_break = false; 121601e04c3fSmrg nir_store_var(&b->nb, fall_var, nir_imm_true(&b->nb), 1); 12177ec681f3Smrg vtn_emit_cf_list_structured(b, &cse->body, fall_var, &has_break, 12187ec681f3Smrg handler); 121901e04c3fSmrg (void)has_break; /* We don't care */ 122001e04c3fSmrg 122101e04c3fSmrg nir_pop_if(&b->nb, case_if); 122201e04c3fSmrg } 122301e04c3fSmrg 122401e04c3fSmrg break; 122501e04c3fSmrg } 122601e04c3fSmrg 122701e04c3fSmrg default: 122801e04c3fSmrg vtn_fail("Invalid CF node type"); 122901e04c3fSmrg } 123001e04c3fSmrg } 123101e04c3fSmrg} 123201e04c3fSmrg 12337ec681f3Smrgstatic struct nir_block * 12347ec681f3Smrgvtn_new_unstructured_block(struct vtn_builder *b, struct vtn_function *func) 12357ec681f3Smrg{ 12367ec681f3Smrg struct nir_block *n = nir_block_create(b->shader); 12377ec681f3Smrg exec_list_push_tail(&func->nir_func->impl->body, &n->cf_node.node); 12387ec681f3Smrg n->cf_node.parent = &func->nir_func->impl->cf_node; 12397ec681f3Smrg return n; 12407ec681f3Smrg} 12417ec681f3Smrg 12427ec681f3Smrgstatic void 12437ec681f3Smrgvtn_add_unstructured_block(struct vtn_builder *b, 12447ec681f3Smrg struct vtn_function *func, 12457ec681f3Smrg struct list_head *work_list, 12467ec681f3Smrg struct vtn_block *block) 12477ec681f3Smrg{ 12487ec681f3Smrg if (!block->block) { 12497ec681f3Smrg block->block = vtn_new_unstructured_block(b, func); 12507ec681f3Smrg list_addtail(&block->node.link, work_list); 12517ec681f3Smrg } 12527ec681f3Smrg} 12537ec681f3Smrg 12547ec681f3Smrgstatic void 12557ec681f3Smrgvtn_emit_cf_func_unstructured(struct vtn_builder *b, struct vtn_function *func, 12567ec681f3Smrg vtn_instruction_handler handler) 12577ec681f3Smrg{ 12587ec681f3Smrg struct list_head work_list; 12597ec681f3Smrg list_inithead(&work_list); 12607ec681f3Smrg 12617ec681f3Smrg func->start_block->block = nir_start_block(func->nir_func->impl); 12627ec681f3Smrg list_addtail(&func->start_block->node.link, &work_list); 12637ec681f3Smrg while (!list_is_empty(&work_list)) { 12647ec681f3Smrg struct vtn_block *block = 12657ec681f3Smrg list_first_entry(&work_list, struct vtn_block, node.link); 12667ec681f3Smrg list_del(&block->node.link); 12677ec681f3Smrg 12687ec681f3Smrg vtn_assert(block->block); 12697ec681f3Smrg 12707ec681f3Smrg const uint32_t *block_start = block->label; 12717ec681f3Smrg const uint32_t *block_end = block->branch; 12727ec681f3Smrg 12737ec681f3Smrg b->nb.cursor = nir_after_block(block->block); 12747ec681f3Smrg block_start = vtn_foreach_instruction(b, block_start, block_end, 12757ec681f3Smrg vtn_handle_phis_first_pass); 12767ec681f3Smrg vtn_foreach_instruction(b, block_start, block_end, handler); 12777ec681f3Smrg block->end_nop = nir_nop(&b->nb); 12787ec681f3Smrg 12797ec681f3Smrg SpvOp op = *block_end & SpvOpCodeMask; 12807ec681f3Smrg switch (op) { 12817ec681f3Smrg case SpvOpBranch: { 12827ec681f3Smrg struct vtn_block *branch_block = vtn_block(b, block->branch[1]); 12837ec681f3Smrg vtn_add_unstructured_block(b, func, &work_list, branch_block); 12847ec681f3Smrg nir_goto(&b->nb, branch_block->block); 12857ec681f3Smrg break; 12867ec681f3Smrg } 12877ec681f3Smrg 12887ec681f3Smrg case SpvOpBranchConditional: { 12897ec681f3Smrg nir_ssa_def *cond = vtn_ssa_value(b, block->branch[1])->def; 12907ec681f3Smrg struct vtn_block *then_block = vtn_block(b, block->branch[2]); 12917ec681f3Smrg struct vtn_block *else_block = vtn_block(b, block->branch[3]); 12927ec681f3Smrg 12937ec681f3Smrg vtn_add_unstructured_block(b, func, &work_list, then_block); 12947ec681f3Smrg if (then_block == else_block) { 12957ec681f3Smrg nir_goto(&b->nb, then_block->block); 12967ec681f3Smrg } else { 12977ec681f3Smrg vtn_add_unstructured_block(b, func, &work_list, else_block); 12987ec681f3Smrg nir_goto_if(&b->nb, then_block->block, nir_src_for_ssa(cond), 12997ec681f3Smrg else_block->block); 13007ec681f3Smrg } 13017ec681f3Smrg 13027ec681f3Smrg break; 13037ec681f3Smrg } 13047ec681f3Smrg 13057ec681f3Smrg case SpvOpSwitch: { 13067ec681f3Smrg struct list_head cases; 13077ec681f3Smrg list_inithead(&cases); 13087ec681f3Smrg vtn_parse_switch(b, NULL, block->branch, &cases); 13097ec681f3Smrg 13107ec681f3Smrg nir_ssa_def *sel = vtn_get_nir_ssa(b, block->branch[1]); 13117ec681f3Smrg 13127ec681f3Smrg struct vtn_case *def = NULL; 13137ec681f3Smrg vtn_foreach_cf_node(case_node, &cases) { 13147ec681f3Smrg struct vtn_case *cse = vtn_cf_node_as_case(case_node); 13157ec681f3Smrg if (cse->is_default) { 13167ec681f3Smrg assert(def == NULL); 13177ec681f3Smrg def = cse; 13187ec681f3Smrg continue; 13197ec681f3Smrg } 13207ec681f3Smrg 13217ec681f3Smrg nir_ssa_def *cond = nir_imm_false(&b->nb); 13227ec681f3Smrg util_dynarray_foreach(&cse->values, uint64_t, val) 13237ec681f3Smrg cond = nir_ior(&b->nb, cond, nir_ieq_imm(&b->nb, sel, *val)); 13247ec681f3Smrg 13257ec681f3Smrg /* block for the next check */ 13267ec681f3Smrg nir_block *e = vtn_new_unstructured_block(b, func); 13277ec681f3Smrg vtn_add_unstructured_block(b, func, &work_list, cse->block); 13287ec681f3Smrg 13297ec681f3Smrg /* add branching */ 13307ec681f3Smrg nir_goto_if(&b->nb, cse->block->block, nir_src_for_ssa(cond), e); 13317ec681f3Smrg b->nb.cursor = nir_after_block(e); 13327ec681f3Smrg } 13337ec681f3Smrg 13347ec681f3Smrg vtn_assert(def != NULL); 13357ec681f3Smrg vtn_add_unstructured_block(b, func, &work_list, def->block); 13367ec681f3Smrg 13377ec681f3Smrg /* now that all cases are handled, branch into the default block */ 13387ec681f3Smrg nir_goto(&b->nb, def->block->block); 13397ec681f3Smrg break; 13407ec681f3Smrg } 13417ec681f3Smrg 13427ec681f3Smrg case SpvOpKill: { 13437ec681f3Smrg nir_discard(&b->nb); 13447ec681f3Smrg nir_goto(&b->nb, b->func->nir_func->impl->end_block); 13457ec681f3Smrg break; 13467ec681f3Smrg } 13477ec681f3Smrg 13487ec681f3Smrg case SpvOpUnreachable: 13497ec681f3Smrg case SpvOpReturn: 13507ec681f3Smrg case SpvOpReturnValue: { 13517ec681f3Smrg vtn_emit_ret_store(b, block); 13527ec681f3Smrg nir_goto(&b->nb, b->func->nir_func->impl->end_block); 13537ec681f3Smrg break; 13547ec681f3Smrg } 13557ec681f3Smrg 13567ec681f3Smrg default: 13577ec681f3Smrg vtn_fail("Unhandled opcode %s", spirv_op_to_string(op)); 13587ec681f3Smrg } 13597ec681f3Smrg } 13607ec681f3Smrg} 13617ec681f3Smrg 136201e04c3fSmrgvoid 136301e04c3fSmrgvtn_function_emit(struct vtn_builder *b, struct vtn_function *func, 136401e04c3fSmrg vtn_instruction_handler instruction_handler) 136501e04c3fSmrg{ 13667ec681f3Smrg static int force_unstructured = -1; 13677ec681f3Smrg if (force_unstructured < 0) { 13687ec681f3Smrg force_unstructured = 13697ec681f3Smrg env_var_as_boolean("MESA_SPIRV_FORCE_UNSTRUCTURED", false); 13707ec681f3Smrg } 13717ec681f3Smrg 13727ec681f3Smrg nir_function_impl *impl = func->nir_func->impl; 13737ec681f3Smrg nir_builder_init(&b->nb, impl); 137401e04c3fSmrg b->func = func; 13757ec681f3Smrg b->nb.cursor = nir_after_cf_list(&impl->body); 13767e102996Smaya b->nb.exact = b->exact; 13777e102996Smaya b->phi_table = _mesa_pointer_hash_table_create(b); 137801e04c3fSmrg 13797ec681f3Smrg if (b->shader->info.stage == MESA_SHADER_KERNEL || force_unstructured) { 13807ec681f3Smrg impl->structured = false; 13817ec681f3Smrg vtn_emit_cf_func_unstructured(b, func, instruction_handler); 13827ec681f3Smrg } else { 13837ec681f3Smrg vtn_emit_cf_list_structured(b, &func->body, NULL, NULL, 13847ec681f3Smrg instruction_handler); 13857ec681f3Smrg } 138601e04c3fSmrg 138701e04c3fSmrg vtn_foreach_instruction(b, func->start_block->label, func->end, 138801e04c3fSmrg vtn_handle_phi_second_pass); 138901e04c3fSmrg 13907ec681f3Smrg if (func->nir_func->impl->structured) 13917ec681f3Smrg nir_copy_prop_impl(impl); 13927ec681f3Smrg nir_rematerialize_derefs_in_use_blocks_impl(impl); 13937e102996Smaya 13947ec681f3Smrg /* 13957ec681f3Smrg * There are some cases where we need to repair SSA to insert 13967ec681f3Smrg * the needed phi nodes: 13977ec681f3Smrg * 13987ec681f3Smrg * - Continue blocks for loops get inserted before the body of the loop 13997ec681f3Smrg * but instructions in the continue may use SSA defs in the loop body. 14007ec681f3Smrg * 14017ec681f3Smrg * - Early termination instructions `OpKill` and `OpTerminateInvocation`, 14027ec681f3Smrg * in NIR. They're represented by regular intrinsics with no control-flow 14037ec681f3Smrg * semantics. This means that the SSA form from the SPIR-V may not 14047ec681f3Smrg * 100% match NIR. 14057ec681f3Smrg * 14067ec681f3Smrg * - Switches with only default case may also define SSA which may 14077ec681f3Smrg * subsequently be used out of the switch. 140801e04c3fSmrg */ 14097ec681f3Smrg if (func->nir_func->impl->structured) 14107ec681f3Smrg nir_repair_ssa_impl(impl); 141101e04c3fSmrg 141201e04c3fSmrg func->emitted = true; 141301e04c3fSmrg} 1414