Path: blob/21.2-virgl/src/compiler/spirv/vtn_cfg.c
4545 views
/*1* Copyright © 2015 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include "vtn_private.h"24#include "spirv_info.h"25#include "nir/nir_vla.h"26#include "util/debug.h"2728static struct vtn_block *29vtn_block(struct vtn_builder *b, uint32_t value_id)30{31return vtn_value(b, value_id, vtn_value_type_block)->block;32}3334static unsigned35glsl_type_count_function_params(const struct glsl_type *type)36{37if (glsl_type_is_vector_or_scalar(type)) {38return 1;39} else if (glsl_type_is_array_or_matrix(type)) {40return glsl_get_length(type) *41glsl_type_count_function_params(glsl_get_array_element(type));42} else {43assert(glsl_type_is_struct_or_ifc(type));44unsigned count = 0;45unsigned elems = glsl_get_length(type);46for (unsigned i = 0; i < elems; i++) {47const struct glsl_type *elem_type = glsl_get_struct_field(type, i);48count += glsl_type_count_function_params(elem_type);49}50return count;51}52}5354static void55glsl_type_add_to_function_params(const struct glsl_type *type,56nir_function *func,57unsigned *param_idx)58{59if (glsl_type_is_vector_or_scalar(type)) {60func->params[(*param_idx)++] = (nir_parameter) {61.num_components = glsl_get_vector_elements(type),62.bit_size = glsl_get_bit_size(type),63};64} else if (glsl_type_is_array_or_matrix(type)) {65unsigned elems = glsl_get_length(type);66const struct glsl_type *elem_type = glsl_get_array_element(type);67for (unsigned i = 0; i < elems; i++)68glsl_type_add_to_function_params(elem_type,func, param_idx);69} else {70assert(glsl_type_is_struct_or_ifc(type));71unsigned elems = glsl_get_length(type);72for (unsigned i = 0; i < elems; i++) {73const struct glsl_type *elem_type = glsl_get_struct_field(type, i);74glsl_type_add_to_function_params(elem_type, func, param_idx);75}76}77}7879static void80vtn_ssa_value_add_to_call_params(struct vtn_builder *b,81struct vtn_ssa_value *value,82nir_call_instr *call,83unsigned *param_idx)84{85if (glsl_type_is_vector_or_scalar(value->type)) {86call->params[(*param_idx)++] = nir_src_for_ssa(value->def);87} else {88unsigned elems = glsl_get_length(value->type);89for (unsigned i = 0; i < elems; i++) {90vtn_ssa_value_add_to_call_params(b, value->elems[i],91call, param_idx);92}93}94}9596static void97vtn_ssa_value_load_function_param(struct vtn_builder *b,98struct vtn_ssa_value *value,99unsigned *param_idx)100{101if (glsl_type_is_vector_or_scalar(value->type)) {102value->def = nir_load_param(&b->nb, (*param_idx)++);103} else {104unsigned elems = glsl_get_length(value->type);105for (unsigned i = 0; i < elems; i++)106vtn_ssa_value_load_function_param(b, value->elems[i], param_idx);107}108}109110void111vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode,112const uint32_t *w, unsigned count)113{114struct vtn_function *vtn_callee =115vtn_value(b, w[3], vtn_value_type_function)->func;116117vtn_callee->referenced = true;118119nir_call_instr *call = nir_call_instr_create(b->nb.shader,120vtn_callee->nir_func);121122unsigned param_idx = 0;123124nir_deref_instr *ret_deref = NULL;125struct vtn_type *ret_type = vtn_callee->type->return_type;126if (ret_type->base_type != vtn_base_type_void) {127nir_variable *ret_tmp =128nir_local_variable_create(b->nb.impl,129glsl_get_bare_type(ret_type->type),130"return_tmp");131ret_deref = nir_build_deref_var(&b->nb, ret_tmp);132call->params[param_idx++] = nir_src_for_ssa(&ret_deref->dest.ssa);133}134135for (unsigned i = 0; i < vtn_callee->type->length; i++) {136vtn_ssa_value_add_to_call_params(b, vtn_ssa_value(b, w[4 + i]),137call, ¶m_idx);138}139assert(param_idx == call->num_params);140141nir_builder_instr_insert(&b->nb, &call->instr);142143if (ret_type->base_type == vtn_base_type_void) {144vtn_push_value(b, w[2], vtn_value_type_undef);145} else {146vtn_push_ssa_value(b, w[2], vtn_local_load(b, ret_deref, 0));147}148}149150static bool151vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode,152const uint32_t *w, unsigned count)153{154switch (opcode) {155case SpvOpFunction: {156vtn_assert(b->func == NULL);157b->func = rzalloc(b, struct vtn_function);158159b->func->node.type = vtn_cf_node_type_function;160b->func->node.parent = NULL;161list_inithead(&b->func->body);162b->func->control = w[3];163164UNUSED const struct glsl_type *result_type = vtn_get_type(b, w[1])->type;165struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_function);166val->func = b->func;167168b->func->type = vtn_get_type(b, w[4]);169const struct vtn_type *func_type = b->func->type;170171vtn_assert(func_type->return_type->type == result_type);172173nir_function *func =174nir_function_create(b->shader, ralloc_strdup(b->shader, val->name));175176unsigned num_params = 0;177for (unsigned i = 0; i < func_type->length; i++)178num_params += glsl_type_count_function_params(func_type->params[i]->type);179180/* Add one parameter for the function return value */181if (func_type->return_type->base_type != vtn_base_type_void)182num_params++;183184func->num_params = num_params;185func->params = ralloc_array(b->shader, nir_parameter, num_params);186187unsigned idx = 0;188if (func_type->return_type->base_type != vtn_base_type_void) {189nir_address_format addr_format =190vtn_mode_to_address_format(b, vtn_variable_mode_function);191/* The return value is a regular pointer */192func->params[idx++] = (nir_parameter) {193.num_components = nir_address_format_num_components(addr_format),194.bit_size = nir_address_format_bit_size(addr_format),195};196}197198for (unsigned i = 0; i < func_type->length; i++)199glsl_type_add_to_function_params(func_type->params[i]->type, func, &idx);200assert(idx == num_params);201202b->func->nir_func = func;203204/* Set up a nir_function_impl and the builder so we can load arguments205* directly in our OpFunctionParameter handler.206*/207nir_function_impl *impl = nir_function_impl_create(func);208nir_builder_init(&b->nb, impl);209b->nb.cursor = nir_before_cf_list(&impl->body);210b->nb.exact = b->exact;211212b->func_param_idx = 0;213214/* The return value is the first parameter */215if (func_type->return_type->base_type != vtn_base_type_void)216b->func_param_idx++;217break;218}219220case SpvOpFunctionEnd:221b->func->end = w;222if (b->func->start_block == NULL) {223/* In this case, the function didn't have any actual blocks. It's224* just a prototype so delete the function_impl.225*/226b->func->nir_func->impl = NULL;227}228b->func = NULL;229break;230231case SpvOpFunctionParameter: {232vtn_assert(b->func_param_idx < b->func->nir_func->num_params);233struct vtn_type *type = vtn_get_type(b, w[1]);234struct vtn_ssa_value *value = vtn_create_ssa_value(b, type->type);235vtn_ssa_value_load_function_param(b, value, &b->func_param_idx);236vtn_push_ssa_value(b, w[2], value);237break;238}239240case SpvOpLabel: {241vtn_assert(b->block == NULL);242b->block = rzalloc(b, struct vtn_block);243b->block->node.type = vtn_cf_node_type_block;244b->block->label = w;245vtn_push_value(b, w[1], vtn_value_type_block)->block = b->block;246247if (b->func->start_block == NULL) {248/* This is the first block encountered for this function. In this249* case, we set the start block and add it to the list of250* implemented functions that we'll walk later.251*/252b->func->start_block = b->block;253list_addtail(&b->func->node.link, &b->functions);254}255break;256}257258case SpvOpSelectionMerge:259case SpvOpLoopMerge:260vtn_assert(b->block && b->block->merge == NULL);261b->block->merge = w;262break;263264case SpvOpBranch:265case SpvOpBranchConditional:266case SpvOpSwitch:267case SpvOpKill:268case SpvOpTerminateInvocation:269case SpvOpIgnoreIntersectionKHR:270case SpvOpTerminateRayKHR:271case SpvOpReturn:272case SpvOpReturnValue:273case SpvOpUnreachable:274vtn_assert(b->block && b->block->branch == NULL);275b->block->branch = w;276b->block = NULL;277break;278279default:280/* Continue on as per normal */281return true;282}283284return true;285}286287/* This function performs a depth-first search of the cases and puts them288* in fall-through order.289*/290static void291vtn_order_case(struct vtn_switch *swtch, struct vtn_case *cse)292{293if (cse->visited)294return;295296cse->visited = true;297298list_del(&cse->node.link);299300if (cse->fallthrough) {301vtn_order_case(swtch, cse->fallthrough);302303/* If we have a fall-through, place this case right before the case it304* falls through to. This ensures that fallthroughs come one after305* the other. These two can never get separated because that would306* imply something else falling through to the same case. Also, this307* can't break ordering because the DFS ensures that this case is308* visited before anything that falls through to it.309*/310list_addtail(&cse->node.link, &cse->fallthrough->node.link);311} else {312list_add(&cse->node.link, &swtch->cases);313}314}315316static void317vtn_switch_order_cases(struct vtn_switch *swtch)318{319struct list_head cases;320list_replace(&swtch->cases, &cases);321list_inithead(&swtch->cases);322while (!list_is_empty(&cases)) {323struct vtn_case *cse =324list_first_entry(&cases, struct vtn_case, node.link);325vtn_order_case(swtch, cse);326}327}328329static void330vtn_block_set_merge_cf_node(struct vtn_builder *b, struct vtn_block *block,331struct vtn_cf_node *cf_node)332{333vtn_fail_if(block->merge_cf_node != NULL,334"The merge block declared by a header block cannot be a "335"merge block declared by any other header block.");336337block->merge_cf_node = cf_node;338}339340#define VTN_DECL_CF_NODE_FIND(_type) \341static inline struct vtn_##_type * \342vtn_cf_node_find_##_type(struct vtn_cf_node *node) \343{ \344while (node && node->type != vtn_cf_node_type_##_type) \345node = node->parent; \346return (struct vtn_##_type *)node; \347}348349VTN_DECL_CF_NODE_FIND(if)350VTN_DECL_CF_NODE_FIND(loop)351VTN_DECL_CF_NODE_FIND(case)352VTN_DECL_CF_NODE_FIND(switch)353VTN_DECL_CF_NODE_FIND(function)354355static enum vtn_branch_type356vtn_handle_branch(struct vtn_builder *b,357struct vtn_cf_node *cf_parent,358struct vtn_block *target_block)359{360struct vtn_loop *loop = vtn_cf_node_find_loop(cf_parent);361362/* Detect a loop back-edge first. That way none of the code below363* accidentally operates on a loop back-edge.364*/365if (loop && target_block == loop->header_block)366return vtn_branch_type_loop_back_edge;367368/* Try to detect fall-through */369if (target_block->switch_case) {370/* When it comes to handling switch cases, we can break calls to371* vtn_handle_branch into two cases: calls from within a case construct372* and calls for the jump to each case construct. In the second case,373* cf_parent is the vtn_switch itself and vtn_cf_node_find_case() will374* return the outer switch case in which this switch is contained. It's375* fine if the target block is a switch case from an outer switch as376* long as it is also the switch break for this switch.377*/378struct vtn_case *switch_case = vtn_cf_node_find_case(cf_parent);379380/* This doesn't get called for the OpSwitch */381vtn_fail_if(switch_case == NULL,382"A switch case can only be entered through an OpSwitch or "383"falling through from another switch case.");384385/* Because block->switch_case is only set on the entry block for a given386* switch case, we only ever get here if we're jumping to the start of a387* switch case. It's possible, however, that a switch case could jump388* to itself via a back-edge. That *should* get caught by the loop389* handling case above but if we have a back edge without a loop merge,390* we could en up here.391*/392vtn_fail_if(target_block->switch_case == switch_case,393"A switch cannot fall-through to itself. Likely, there is "394"a back-edge which is not to a loop header.");395396vtn_fail_if(target_block->switch_case->node.parent !=397switch_case->node.parent,398"A switch case fall-through must come from the same "399"OpSwitch construct");400401vtn_fail_if(switch_case->fallthrough != NULL &&402switch_case->fallthrough != target_block->switch_case,403"Each case construct can have at most one branch to "404"another case construct");405406switch_case->fallthrough = target_block->switch_case;407408/* We don't immediately return vtn_branch_type_switch_fallthrough409* because it may also be a loop or switch break for an inner loop or410* switch and that takes precedence.411*/412}413414if (loop && target_block == loop->cont_block)415return vtn_branch_type_loop_continue;416417/* We walk blocks as a breadth-first search on the control-flow construct418* tree where, when we find a construct, we add the vtn_cf_node for that419* construct and continue iterating at the merge target block (if any).420* Therefore, we want merges whose with parent == cf_parent to be treated421* as regular branches. We only want to consider merges if they break out422* of the current CF construct.423*/424if (target_block->merge_cf_node != NULL &&425target_block->merge_cf_node->parent != cf_parent) {426switch (target_block->merge_cf_node->type) {427case vtn_cf_node_type_if:428for (struct vtn_cf_node *node = cf_parent;429node != target_block->merge_cf_node; node = node->parent) {430vtn_fail_if(node == NULL || node->type != vtn_cf_node_type_if,431"Branching to the merge block of a selection "432"construct can only be used to break out of a "433"selection construct");434435struct vtn_if *if_stmt = vtn_cf_node_as_if(node);436437/* This should be guaranteed by our iteration */438assert(if_stmt->merge_block != target_block);439440vtn_fail_if(if_stmt->merge_block != NULL,441"Branching to the merge block of a selection "442"construct can only be used to break out of the "443"inner most nested selection level");444}445return vtn_branch_type_if_merge;446447case vtn_cf_node_type_loop:448vtn_fail_if(target_block->merge_cf_node != &loop->node,449"Loop breaks can only break out of the inner most "450"nested loop level");451return vtn_branch_type_loop_break;452453case vtn_cf_node_type_switch: {454struct vtn_switch *swtch = vtn_cf_node_find_switch(cf_parent);455vtn_fail_if(target_block->merge_cf_node != &swtch->node,456"Switch breaks can only break out of the inner most "457"nested switch level");458return vtn_branch_type_switch_break;459}460461default:462unreachable("Invalid CF node type for a merge");463}464}465466if (target_block->switch_case)467return vtn_branch_type_switch_fallthrough;468469return vtn_branch_type_none;470}471472struct vtn_cfg_work_item {473struct list_head link;474475struct vtn_cf_node *cf_parent;476struct list_head *cf_list;477struct vtn_block *start_block;478};479480static void481vtn_add_cfg_work_item(struct vtn_builder *b,482struct list_head *work_list,483struct vtn_cf_node *cf_parent,484struct list_head *cf_list,485struct vtn_block *start_block)486{487struct vtn_cfg_work_item *work = ralloc(b, struct vtn_cfg_work_item);488work->cf_parent = cf_parent;489work->cf_list = cf_list;490work->start_block = start_block;491list_addtail(&work->link, work_list);492}493494/* returns the default block */495static void496vtn_parse_switch(struct vtn_builder *b,497struct vtn_switch *swtch,498const uint32_t *branch,499struct list_head *case_list)500{501const uint32_t *branch_end = branch + (branch[0] >> SpvWordCountShift);502503struct vtn_value *sel_val = vtn_untyped_value(b, branch[1]);504vtn_fail_if(!sel_val->type ||505sel_val->type->base_type != vtn_base_type_scalar,506"Selector of OpSwitch must have a type of OpTypeInt");507508nir_alu_type sel_type =509nir_get_nir_type_for_glsl_type(sel_val->type->type);510vtn_fail_if(nir_alu_type_get_base_type(sel_type) != nir_type_int &&511nir_alu_type_get_base_type(sel_type) != nir_type_uint,512"Selector of OpSwitch must have a type of OpTypeInt");513514struct hash_table *block_to_case = _mesa_pointer_hash_table_create(b);515516bool is_default = true;517const unsigned bitsize = nir_alu_type_get_type_size(sel_type);518for (const uint32_t *w = branch + 2; w < branch_end;) {519uint64_t literal = 0;520if (!is_default) {521if (bitsize <= 32) {522literal = *(w++);523} else {524assert(bitsize == 64);525literal = vtn_u64_literal(w);526w += 2;527}528}529struct vtn_block *case_block = vtn_block(b, *(w++));530531struct hash_entry *case_entry =532_mesa_hash_table_search(block_to_case, case_block);533534struct vtn_case *cse;535if (case_entry) {536cse = case_entry->data;537} else {538cse = rzalloc(b, struct vtn_case);539540cse->node.type = vtn_cf_node_type_case;541cse->node.parent = swtch ? &swtch->node : NULL;542cse->block = case_block;543list_inithead(&cse->body);544util_dynarray_init(&cse->values, b);545546list_addtail(&cse->node.link, case_list);547_mesa_hash_table_insert(block_to_case, case_block, cse);548}549550if (is_default) {551cse->is_default = true;552} else {553util_dynarray_append(&cse->values, uint64_t, literal);554}555556is_default = false;557}558559_mesa_hash_table_destroy(block_to_case, NULL);560}561562/* Processes a block and returns the next block to process or NULL if we've563* reached the end of the construct.564*/565static struct vtn_block *566vtn_process_block(struct vtn_builder *b,567struct list_head *work_list,568struct vtn_cf_node *cf_parent,569struct list_head *cf_list,570struct vtn_block *block)571{572if (!list_is_empty(cf_list)) {573/* vtn_process_block() acts like an iterator: it processes the given574* block and then returns the next block to process. For a given575* control-flow construct, vtn_build_cfg() calls vtn_process_block()576* repeatedly until it finally returns NULL. Therefore, we know that577* the only blocks on which vtn_process_block() can be called are either578* the first block in a construct or a block that vtn_process_block()579* returned for the current construct. If cf_list is empty then we know580* that we're processing the first block in the construct and we have to581* add it to the list.582*583* If cf_list is not empty, then it must be the block returned by the584* previous call to vtn_process_block(). We know a priori that585* vtn_process_block only returns either normal branches586* (vtn_branch_type_none) or merge target blocks.587*/588switch (vtn_handle_branch(b, cf_parent, block)) {589case vtn_branch_type_none:590/* For normal branches, we want to process them and add them to the591* current construct. Merge target blocks also look like normal592* branches from the perspective of this construct. See also593* vtn_handle_branch().594*/595break;596597case vtn_branch_type_loop_continue:598case vtn_branch_type_switch_fallthrough:599/* The two cases where we can get early exits from a construct that600* are not to that construct's merge target are loop continues and601* switch fall-throughs. In these cases, we need to break out of the602* current construct by returning NULL.603*/604return NULL;605606default:607/* The only way we can get here is if something was used as two kinds608* of merges at the same time and that's illegal.609*/610vtn_fail("A block was used as a merge target from two or more "611"structured control-flow constructs");612}613}614615/* Once a block has been processed, it is placed into and the list link616* will point to something non-null. If we see a node we've already617* processed here, it either exists in multiple functions or it's an618* invalid back-edge.619*/620if (block->node.parent != NULL) {621vtn_fail_if(vtn_cf_node_find_function(&block->node) !=622vtn_cf_node_find_function(cf_parent),623"A block cannot exist in two functions at the "624"same time");625626vtn_fail("Invalid back or cross-edge in the CFG");627}628629if (block->merge && (*block->merge & SpvOpCodeMask) == SpvOpLoopMerge &&630block->loop == NULL) {631vtn_fail_if((*block->branch & SpvOpCodeMask) != SpvOpBranch &&632(*block->branch & SpvOpCodeMask) != SpvOpBranchConditional,633"An OpLoopMerge instruction must immediately precede "634"either an OpBranch or OpBranchConditional instruction.");635636struct vtn_loop *loop = rzalloc(b, struct vtn_loop);637638loop->node.type = vtn_cf_node_type_loop;639loop->node.parent = cf_parent;640list_inithead(&loop->body);641list_inithead(&loop->cont_body);642loop->header_block = block;643loop->break_block = vtn_block(b, block->merge[1]);644loop->cont_block = vtn_block(b, block->merge[2]);645loop->control = block->merge[3];646647list_addtail(&loop->node.link, cf_list);648block->loop = loop;649650/* Note: The work item for the main loop body will start with the651* current block as its start block. If we weren't careful, we would652* get here again and end up in an infinite loop. This is why we set653* block->loop above and check for it before creating one. This way,654* we only create the loop once and the second iteration that tries to655* handle this loop goes to the cases below and gets handled as a656* regular block.657*/658vtn_add_cfg_work_item(b, work_list, &loop->node,659&loop->body, loop->header_block);660661/* For continue targets, SPIR-V guarantees the following:662*663* - the Continue Target must dominate the back-edge block664* - the back-edge block must post dominate the Continue Target665*666* If the header block is the same as the continue target, this667* condition is trivially satisfied and there is no real continue668* section.669*/670if (loop->cont_block != loop->header_block) {671vtn_add_cfg_work_item(b, work_list, &loop->node,672&loop->cont_body, loop->cont_block);673}674675vtn_block_set_merge_cf_node(b, loop->break_block, &loop->node);676677return loop->break_block;678}679680/* Add the block to the CF list */681block->node.parent = cf_parent;682list_addtail(&block->node.link, cf_list);683684switch (*block->branch & SpvOpCodeMask) {685case SpvOpBranch: {686struct vtn_block *branch_block = vtn_block(b, block->branch[1]);687688block->branch_type = vtn_handle_branch(b, cf_parent, branch_block);689690if (block->branch_type == vtn_branch_type_none)691return branch_block;692else693return NULL;694}695696case SpvOpReturn:697case SpvOpReturnValue:698block->branch_type = vtn_branch_type_return;699return NULL;700701case SpvOpKill:702block->branch_type = vtn_branch_type_discard;703return NULL;704705case SpvOpTerminateInvocation:706block->branch_type = vtn_branch_type_terminate_invocation;707return NULL;708709case SpvOpIgnoreIntersectionKHR:710block->branch_type = vtn_branch_type_ignore_intersection;711return NULL;712713case SpvOpTerminateRayKHR:714block->branch_type = vtn_branch_type_terminate_ray;715return NULL;716717case SpvOpBranchConditional: {718struct vtn_value *cond_val = vtn_untyped_value(b, block->branch[1]);719vtn_fail_if(!cond_val->type ||720cond_val->type->base_type != vtn_base_type_scalar ||721cond_val->type->type != glsl_bool_type(),722"Condition must be a Boolean type scalar");723724struct vtn_if *if_stmt = rzalloc(b, struct vtn_if);725726if_stmt->node.type = vtn_cf_node_type_if;727if_stmt->node.parent = cf_parent;728if_stmt->header_block = block;729list_inithead(&if_stmt->then_body);730list_inithead(&if_stmt->else_body);731732list_addtail(&if_stmt->node.link, cf_list);733734if (block->merge &&735(*block->merge & SpvOpCodeMask) == SpvOpSelectionMerge) {736/* We may not always have a merge block and that merge doesn't737* technically have to be an OpSelectionMerge. We could have a block738* with an OpLoopMerge which ends in an OpBranchConditional.739*/740if_stmt->merge_block = vtn_block(b, block->merge[1]);741vtn_block_set_merge_cf_node(b, if_stmt->merge_block, &if_stmt->node);742743if_stmt->control = block->merge[2];744}745746struct vtn_block *then_block = vtn_block(b, block->branch[2]);747if_stmt->then_type = vtn_handle_branch(b, &if_stmt->node, then_block);748if (if_stmt->then_type == vtn_branch_type_none) {749vtn_add_cfg_work_item(b, work_list, &if_stmt->node,750&if_stmt->then_body, then_block);751}752753struct vtn_block *else_block = vtn_block(b, block->branch[3]);754if (then_block != else_block) {755if_stmt->else_type = vtn_handle_branch(b, &if_stmt->node, else_block);756if (if_stmt->else_type == vtn_branch_type_none) {757vtn_add_cfg_work_item(b, work_list, &if_stmt->node,758&if_stmt->else_body, else_block);759}760}761762return if_stmt->merge_block;763}764765case SpvOpSwitch: {766struct vtn_switch *swtch = rzalloc(b, struct vtn_switch);767768swtch->node.type = vtn_cf_node_type_switch;769swtch->node.parent = cf_parent;770swtch->selector = block->branch[1];771list_inithead(&swtch->cases);772773list_addtail(&swtch->node.link, cf_list);774775/* We may not always have a merge block */776if (block->merge) {777vtn_fail_if((*block->merge & SpvOpCodeMask) != SpvOpSelectionMerge,778"An OpLoopMerge instruction must immediately precede "779"either an OpBranch or OpBranchConditional "780"instruction.");781swtch->break_block = vtn_block(b, block->merge[1]);782vtn_block_set_merge_cf_node(b, swtch->break_block, &swtch->node);783}784785/* First, we go through and record all of the cases. */786vtn_parse_switch(b, swtch, block->branch, &swtch->cases);787788/* Gather the branch types for the switch */789vtn_foreach_cf_node(case_node, &swtch->cases) {790struct vtn_case *cse = vtn_cf_node_as_case(case_node);791792cse->type = vtn_handle_branch(b, &swtch->node, cse->block);793switch (cse->type) {794case vtn_branch_type_none:795/* This is a "real" cases which has stuff in it */796vtn_fail_if(cse->block->switch_case != NULL,797"OpSwitch has a case which is also in another "798"OpSwitch construct");799cse->block->switch_case = cse;800vtn_add_cfg_work_item(b, work_list, &cse->node,801&cse->body, cse->block);802break;803804case vtn_branch_type_switch_break:805case vtn_branch_type_loop_break:806case vtn_branch_type_loop_continue:807/* Switch breaks as well as loop breaks and continues can be808* used to break out of a switch construct or as direct targets809* of the OpSwitch.810*/811break;812813default:814vtn_fail("Target of OpSwitch is not a valid structured exit "815"from the switch construct.");816}817}818819return swtch->break_block;820}821822case SpvOpUnreachable:823return NULL;824825default:826vtn_fail("Block did not end with a valid branch instruction");827}828}829830void831vtn_build_cfg(struct vtn_builder *b, const uint32_t *words, const uint32_t *end)832{833vtn_foreach_instruction(b, words, end,834vtn_cfg_handle_prepass_instruction);835836if (b->shader->info.stage == MESA_SHADER_KERNEL)837return;838839vtn_foreach_cf_node(func_node, &b->functions) {840struct vtn_function *func = vtn_cf_node_as_function(func_node);841842/* We build the CFG for each function by doing a breadth-first search on843* the control-flow graph. We keep track of our state using a worklist.844* Doing a BFS ensures that we visit each structured control-flow845* construct and its merge node before we visit the stuff inside the846* construct.847*/848struct list_head work_list;849list_inithead(&work_list);850vtn_add_cfg_work_item(b, &work_list, &func->node, &func->body,851func->start_block);852853while (!list_is_empty(&work_list)) {854struct vtn_cfg_work_item *work =855list_first_entry(&work_list, struct vtn_cfg_work_item, link);856list_del(&work->link);857858for (struct vtn_block *block = work->start_block; block; ) {859block = vtn_process_block(b, &work_list, work->cf_parent,860work->cf_list, block);861}862}863}864}865866static bool867vtn_handle_phis_first_pass(struct vtn_builder *b, SpvOp opcode,868const uint32_t *w, unsigned count)869{870if (opcode == SpvOpLabel)871return true; /* Nothing to do */872873/* If this isn't a phi node, stop. */874if (opcode != SpvOpPhi)875return false;876877/* For handling phi nodes, we do a poor-man's out-of-ssa on the spot.878* For each phi, we create a variable with the appropreate type and879* do a load from that variable. Then, in a second pass, we add880* stores to that variable to each of the predecessor blocks.881*882* We could do something more intelligent here. However, in order to883* handle loops and things properly, we really need dominance884* information. It would end up basically being the into-SSA885* algorithm all over again. It's easier if we just let886* lower_vars_to_ssa do that for us instead of repeating it here.887*/888struct vtn_type *type = vtn_get_type(b, w[1]);889nir_variable *phi_var =890nir_local_variable_create(b->nb.impl, type->type, "phi");891_mesa_hash_table_insert(b->phi_table, w, phi_var);892893vtn_push_ssa_value(b, w[2],894vtn_local_load(b, nir_build_deref_var(&b->nb, phi_var), 0));895896return true;897}898899static bool900vtn_handle_phi_second_pass(struct vtn_builder *b, SpvOp opcode,901const uint32_t *w, unsigned count)902{903if (opcode != SpvOpPhi)904return true;905906struct hash_entry *phi_entry = _mesa_hash_table_search(b->phi_table, w);907908/* It's possible that this phi is in an unreachable block in which case it909* may never have been emitted and therefore may not be in the hash table.910* In this case, there's no var for it and it's safe to just bail.911*/912if (phi_entry == NULL)913return true;914915nir_variable *phi_var = phi_entry->data;916917for (unsigned i = 3; i < count; i += 2) {918struct vtn_block *pred = vtn_block(b, w[i + 1]);919920/* If block does not have end_nop, that is because it is an unreacheable921* block, and hence it is not worth to handle it */922if (!pred->end_nop)923continue;924925b->nb.cursor = nir_after_instr(&pred->end_nop->instr);926927struct vtn_ssa_value *src = vtn_ssa_value(b, w[i]);928929vtn_local_store(b, src, nir_build_deref_var(&b->nb, phi_var), 0);930}931932return true;933}934935static void936vtn_emit_branch(struct vtn_builder *b, enum vtn_branch_type branch_type,937nir_variable *switch_fall_var, bool *has_switch_break)938{939switch (branch_type) {940case vtn_branch_type_if_merge:941break; /* Nothing to do */942case vtn_branch_type_switch_break:943nir_store_var(&b->nb, switch_fall_var, nir_imm_false(&b->nb), 1);944*has_switch_break = true;945break;946case vtn_branch_type_switch_fallthrough:947break; /* Nothing to do */948case vtn_branch_type_loop_break:949nir_jump(&b->nb, nir_jump_break);950break;951case vtn_branch_type_loop_continue:952nir_jump(&b->nb, nir_jump_continue);953break;954case vtn_branch_type_loop_back_edge:955break;956case vtn_branch_type_return:957nir_jump(&b->nb, nir_jump_return);958break;959case vtn_branch_type_discard:960if (b->convert_discard_to_demote)961nir_demote(&b->nb);962else963nir_discard(&b->nb);964break;965case vtn_branch_type_terminate_invocation:966nir_terminate(&b->nb);967break;968case vtn_branch_type_ignore_intersection:969nir_ignore_ray_intersection(&b->nb);970nir_jump(&b->nb, nir_jump_halt);971break;972case vtn_branch_type_terminate_ray:973nir_terminate_ray(&b->nb);974nir_jump(&b->nb, nir_jump_halt);975break;976default:977vtn_fail("Invalid branch type");978}979}980981static nir_ssa_def *982vtn_switch_case_condition(struct vtn_builder *b, struct vtn_switch *swtch,983nir_ssa_def *sel, struct vtn_case *cse)984{985if (cse->is_default) {986nir_ssa_def *any = nir_imm_false(&b->nb);987vtn_foreach_cf_node(other_node, &swtch->cases) {988struct vtn_case *other = vtn_cf_node_as_case(other_node);989if (other->is_default)990continue;991992any = nir_ior(&b->nb, any,993vtn_switch_case_condition(b, swtch, sel, other));994}995return nir_inot(&b->nb, any);996} else {997nir_ssa_def *cond = nir_imm_false(&b->nb);998util_dynarray_foreach(&cse->values, uint64_t, val)999cond = nir_ior(&b->nb, cond, nir_ieq_imm(&b->nb, sel, *val));1000return cond;1001}1002}10031004static nir_loop_control1005vtn_loop_control(struct vtn_builder *b, struct vtn_loop *vtn_loop)1006{1007if (vtn_loop->control == SpvLoopControlMaskNone)1008return nir_loop_control_none;1009else if (vtn_loop->control & SpvLoopControlDontUnrollMask)1010return nir_loop_control_dont_unroll;1011else if (vtn_loop->control & SpvLoopControlUnrollMask)1012return nir_loop_control_unroll;1013else if (vtn_loop->control & SpvLoopControlDependencyInfiniteMask ||1014vtn_loop->control & SpvLoopControlDependencyLengthMask ||1015vtn_loop->control & SpvLoopControlMinIterationsMask ||1016vtn_loop->control & SpvLoopControlMaxIterationsMask ||1017vtn_loop->control & SpvLoopControlIterationMultipleMask ||1018vtn_loop->control & SpvLoopControlPeelCountMask ||1019vtn_loop->control & SpvLoopControlPartialCountMask) {1020/* We do not do anything special with these yet. */1021return nir_loop_control_none;1022} else {1023vtn_fail("Invalid loop control");1024}1025}10261027static nir_selection_control1028vtn_selection_control(struct vtn_builder *b, struct vtn_if *vtn_if)1029{1030if (vtn_if->control == SpvSelectionControlMaskNone)1031return nir_selection_control_none;1032else if (vtn_if->control & SpvSelectionControlDontFlattenMask)1033return nir_selection_control_dont_flatten;1034else if (vtn_if->control & SpvSelectionControlFlattenMask)1035return nir_selection_control_flatten;1036else1037vtn_fail("Invalid selection control");1038}10391040static void1041vtn_emit_ret_store(struct vtn_builder *b, struct vtn_block *block)1042{1043if ((*block->branch & SpvOpCodeMask) != SpvOpReturnValue)1044return;10451046vtn_fail_if(b->func->type->return_type->base_type == vtn_base_type_void,1047"Return with a value from a function returning void");1048struct vtn_ssa_value *src = vtn_ssa_value(b, block->branch[1]);1049const struct glsl_type *ret_type =1050glsl_get_bare_type(b->func->type->return_type->type);1051nir_deref_instr *ret_deref =1052nir_build_deref_cast(&b->nb, nir_load_param(&b->nb, 0),1053nir_var_function_temp, ret_type, 0);1054vtn_local_store(b, src, ret_deref, 0);1055}10561057static void1058vtn_emit_cf_list_structured(struct vtn_builder *b, struct list_head *cf_list,1059nir_variable *switch_fall_var,1060bool *has_switch_break,1061vtn_instruction_handler handler)1062{1063vtn_foreach_cf_node(node, cf_list) {1064switch (node->type) {1065case vtn_cf_node_type_block: {1066struct vtn_block *block = vtn_cf_node_as_block(node);10671068const uint32_t *block_start = block->label;1069const uint32_t *block_end = block->merge ? block->merge :1070block->branch;10711072block_start = vtn_foreach_instruction(b, block_start, block_end,1073vtn_handle_phis_first_pass);10741075vtn_foreach_instruction(b, block_start, block_end, handler);10761077block->end_nop = nir_nop(&b->nb);10781079vtn_emit_ret_store(b, block);10801081if (block->branch_type != vtn_branch_type_none) {1082vtn_emit_branch(b, block->branch_type,1083switch_fall_var, has_switch_break);1084return;1085}10861087break;1088}10891090case vtn_cf_node_type_if: {1091struct vtn_if *vtn_if = vtn_cf_node_as_if(node);1092const uint32_t *branch = vtn_if->header_block->branch;1093vtn_assert((branch[0] & SpvOpCodeMask) == SpvOpBranchConditional);10941095/* If both branches are the same, just emit the first block, which is1096* the only one we filled when building the CFG.1097*/1098if (branch[2] == branch[3]) {1099vtn_emit_cf_list_structured(b, &vtn_if->then_body,1100switch_fall_var, has_switch_break, handler);1101break;1102}11031104bool sw_break = false;11051106nir_if *nif =1107nir_push_if(&b->nb, vtn_get_nir_ssa(b, branch[1]));11081109nif->control = vtn_selection_control(b, vtn_if);11101111if (vtn_if->then_type == vtn_branch_type_none) {1112vtn_emit_cf_list_structured(b, &vtn_if->then_body,1113switch_fall_var, &sw_break, handler);1114} else {1115vtn_emit_branch(b, vtn_if->then_type, switch_fall_var, &sw_break);1116}11171118nir_push_else(&b->nb, nif);1119if (vtn_if->else_type == vtn_branch_type_none) {1120vtn_emit_cf_list_structured(b, &vtn_if->else_body,1121switch_fall_var, &sw_break, handler);1122} else {1123vtn_emit_branch(b, vtn_if->else_type, switch_fall_var, &sw_break);1124}11251126nir_pop_if(&b->nb, nif);11271128/* If we encountered a switch break somewhere inside of the if,1129* then it would have been handled correctly by calling1130* emit_cf_list or emit_branch for the interrior. However, we1131* need to predicate everything following on wether or not we're1132* still going.1133*/1134if (sw_break) {1135*has_switch_break = true;1136nir_push_if(&b->nb, nir_load_var(&b->nb, switch_fall_var));1137}1138break;1139}11401141case vtn_cf_node_type_loop: {1142struct vtn_loop *vtn_loop = vtn_cf_node_as_loop(node);11431144nir_loop *loop = nir_push_loop(&b->nb);1145loop->control = vtn_loop_control(b, vtn_loop);11461147vtn_emit_cf_list_structured(b, &vtn_loop->body, NULL, NULL, handler);11481149if (!list_is_empty(&vtn_loop->cont_body)) {1150/* If we have a non-trivial continue body then we need to put1151* it at the beginning of the loop with a flag to ensure that1152* it doesn't get executed in the first iteration.1153*/1154nir_variable *do_cont =1155nir_local_variable_create(b->nb.impl, glsl_bool_type(), "cont");11561157b->nb.cursor = nir_before_cf_node(&loop->cf_node);1158nir_store_var(&b->nb, do_cont, nir_imm_false(&b->nb), 1);11591160b->nb.cursor = nir_before_cf_list(&loop->body);11611162nir_if *cont_if =1163nir_push_if(&b->nb, nir_load_var(&b->nb, do_cont));11641165vtn_emit_cf_list_structured(b, &vtn_loop->cont_body, NULL, NULL,1166handler);11671168nir_pop_if(&b->nb, cont_if);11691170nir_store_var(&b->nb, do_cont, nir_imm_true(&b->nb), 1);1171}11721173nir_pop_loop(&b->nb, loop);1174break;1175}11761177case vtn_cf_node_type_switch: {1178struct vtn_switch *vtn_switch = vtn_cf_node_as_switch(node);11791180/* Before we can emit anything, we need to sort the list of cases in1181* fall-through order.1182*/1183vtn_switch_order_cases(vtn_switch);11841185/* First, we create a variable to keep track of whether or not the1186* switch is still going at any given point. Any switch breaks1187* will set this variable to false.1188*/1189nir_variable *fall_var =1190nir_local_variable_create(b->nb.impl, glsl_bool_type(), "fall");1191nir_store_var(&b->nb, fall_var, nir_imm_false(&b->nb), 1);11921193nir_ssa_def *sel = vtn_get_nir_ssa(b, vtn_switch->selector);11941195/* Now we can walk the list of cases and actually emit code */1196vtn_foreach_cf_node(case_node, &vtn_switch->cases) {1197struct vtn_case *cse = vtn_cf_node_as_case(case_node);11981199/* If this case jumps directly to the break block, we don't have1200* to handle the case as the body is empty and doesn't fall1201* through.1202*/1203if (cse->block == vtn_switch->break_block)1204continue;12051206/* Figure out the condition */1207nir_ssa_def *cond =1208vtn_switch_case_condition(b, vtn_switch, sel, cse);1209/* Take fallthrough into account */1210cond = nir_ior(&b->nb, cond, nir_load_var(&b->nb, fall_var));12111212nir_if *case_if = nir_push_if(&b->nb, cond);12131214bool has_break = false;1215nir_store_var(&b->nb, fall_var, nir_imm_true(&b->nb), 1);1216vtn_emit_cf_list_structured(b, &cse->body, fall_var, &has_break,1217handler);1218(void)has_break; /* We don't care */12191220nir_pop_if(&b->nb, case_if);1221}12221223break;1224}12251226default:1227vtn_fail("Invalid CF node type");1228}1229}1230}12311232static struct nir_block *1233vtn_new_unstructured_block(struct vtn_builder *b, struct vtn_function *func)1234{1235struct nir_block *n = nir_block_create(b->shader);1236exec_list_push_tail(&func->nir_func->impl->body, &n->cf_node.node);1237n->cf_node.parent = &func->nir_func->impl->cf_node;1238return n;1239}12401241static void1242vtn_add_unstructured_block(struct vtn_builder *b,1243struct vtn_function *func,1244struct list_head *work_list,1245struct vtn_block *block)1246{1247if (!block->block) {1248block->block = vtn_new_unstructured_block(b, func);1249list_addtail(&block->node.link, work_list);1250}1251}12521253static void1254vtn_emit_cf_func_unstructured(struct vtn_builder *b, struct vtn_function *func,1255vtn_instruction_handler handler)1256{1257struct list_head work_list;1258list_inithead(&work_list);12591260func->start_block->block = nir_start_block(func->nir_func->impl);1261list_addtail(&func->start_block->node.link, &work_list);1262while (!list_is_empty(&work_list)) {1263struct vtn_block *block =1264list_first_entry(&work_list, struct vtn_block, node.link);1265list_del(&block->node.link);12661267vtn_assert(block->block);12681269const uint32_t *block_start = block->label;1270const uint32_t *block_end = block->branch;12711272b->nb.cursor = nir_after_block(block->block);1273block_start = vtn_foreach_instruction(b, block_start, block_end,1274vtn_handle_phis_first_pass);1275vtn_foreach_instruction(b, block_start, block_end, handler);1276block->end_nop = nir_nop(&b->nb);12771278SpvOp op = *block_end & SpvOpCodeMask;1279switch (op) {1280case SpvOpBranch: {1281struct vtn_block *branch_block = vtn_block(b, block->branch[1]);1282vtn_add_unstructured_block(b, func, &work_list, branch_block);1283nir_goto(&b->nb, branch_block->block);1284break;1285}12861287case SpvOpBranchConditional: {1288nir_ssa_def *cond = vtn_ssa_value(b, block->branch[1])->def;1289struct vtn_block *then_block = vtn_block(b, block->branch[2]);1290struct vtn_block *else_block = vtn_block(b, block->branch[3]);12911292vtn_add_unstructured_block(b, func, &work_list, then_block);1293if (then_block == else_block) {1294nir_goto(&b->nb, then_block->block);1295} else {1296vtn_add_unstructured_block(b, func, &work_list, else_block);1297nir_goto_if(&b->nb, then_block->block, nir_src_for_ssa(cond),1298else_block->block);1299}13001301break;1302}13031304case SpvOpSwitch: {1305struct list_head cases;1306list_inithead(&cases);1307vtn_parse_switch(b, NULL, block->branch, &cases);13081309nir_ssa_def *sel = vtn_get_nir_ssa(b, block->branch[1]);13101311struct vtn_case *def = NULL;1312vtn_foreach_cf_node(case_node, &cases) {1313struct vtn_case *cse = vtn_cf_node_as_case(case_node);1314if (cse->is_default) {1315assert(def == NULL);1316def = cse;1317continue;1318}13191320nir_ssa_def *cond = nir_imm_false(&b->nb);1321util_dynarray_foreach(&cse->values, uint64_t, val)1322cond = nir_ior(&b->nb, cond, nir_ieq_imm(&b->nb, sel, *val));13231324/* block for the next check */1325nir_block *e = vtn_new_unstructured_block(b, func);1326vtn_add_unstructured_block(b, func, &work_list, cse->block);13271328/* add branching */1329nir_goto_if(&b->nb, cse->block->block, nir_src_for_ssa(cond), e);1330b->nb.cursor = nir_after_block(e);1331}13321333vtn_assert(def != NULL);1334vtn_add_unstructured_block(b, func, &work_list, def->block);13351336/* now that all cases are handled, branch into the default block */1337nir_goto(&b->nb, def->block->block);1338break;1339}13401341case SpvOpKill: {1342nir_discard(&b->nb);1343nir_goto(&b->nb, b->func->nir_func->impl->end_block);1344break;1345}13461347case SpvOpUnreachable:1348case SpvOpReturn:1349case SpvOpReturnValue: {1350vtn_emit_ret_store(b, block);1351nir_goto(&b->nb, b->func->nir_func->impl->end_block);1352break;1353}13541355default:1356vtn_fail("Unhandled opcode %s", spirv_op_to_string(op));1357}1358}1359}13601361void1362vtn_function_emit(struct vtn_builder *b, struct vtn_function *func,1363vtn_instruction_handler instruction_handler)1364{1365static int force_unstructured = -1;1366if (force_unstructured < 0) {1367force_unstructured =1368env_var_as_boolean("MESA_SPIRV_FORCE_UNSTRUCTURED", false);1369}13701371nir_function_impl *impl = func->nir_func->impl;1372nir_builder_init(&b->nb, impl);1373b->func = func;1374b->nb.cursor = nir_after_cf_list(&impl->body);1375b->nb.exact = b->exact;1376b->phi_table = _mesa_pointer_hash_table_create(b);13771378if (b->shader->info.stage == MESA_SHADER_KERNEL || force_unstructured) {1379impl->structured = false;1380vtn_emit_cf_func_unstructured(b, func, instruction_handler);1381} else {1382vtn_emit_cf_list_structured(b, &func->body, NULL, NULL,1383instruction_handler);1384}13851386vtn_foreach_instruction(b, func->start_block->label, func->end,1387vtn_handle_phi_second_pass);13881389nir_rematerialize_derefs_in_use_blocks_impl(impl);13901391/*1392* There are some cases where we need to repair SSA to insert1393* the needed phi nodes:1394*1395* - Continue blocks for loops get inserted before the body of the loop1396* but instructions in the continue may use SSA defs in the loop body.1397*1398* - Early termination instructions `OpKill` and `OpTerminateInvocation`,1399* in NIR. They're represented by regular intrinsics with no control-flow1400* semantics. This means that the SSA form from the SPIR-V may not1401* 100% match NIR.1402*1403* - Switches with only default case may also define SSA which may1404* subsequently be used out of the switch.1405*/1406if (func->nir_func->impl->structured)1407nir_repair_ssa_impl(impl);14081409func->emitted = true;1410}141114121413