179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand/* 279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * Copyright © 2015 Intel Corporation 379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * 479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * Permission is hereby granted, free of charge, to any person obtaining a 579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * copy of this software and associated documentation files (the "Software"), 679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * to deal in the Software without restriction, including without limitation 779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * the rights to use, copy, modify, merge, publish, distribute, sublicense, 879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * and/or sell copies of the Software, and to permit persons to whom the 979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * Software is furnished to do so, subject to the following conditions: 1079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * 1179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * The above copyright notice and this permission notice (including the next 1279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * paragraph) shall be included in all copies or substantial portions of the 1379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * Software. 1479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * 1579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * IN THE SOFTWARE. 2279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand */ 2379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 2479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand#include "nir.h" 2579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand#include "nir_builder.h" 2679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand#include "nir_control_flow.h" 2779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 2879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandstruct lower_returns_state { 2979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_builder builder; 3079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand struct exec_list *cf_list; 3179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_loop *loop; 3279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_variable *return_flag; 33f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri 34f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri /* This indicates that we have a return which is predicated on some form of 35f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri * control-flow. Since whether or not the return happens can only be 36f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri * determined dynamically at run-time, everything that occurs afterwards 37f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri * needs to be predicated on the return flag variable. 38f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri */ 39f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri bool has_predicated_return; 4079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand}; 4179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 4279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandstatic bool lower_returns_in_cf_list(struct exec_list *cf_list, 4379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand struct lower_returns_state *state); 4479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 4579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandstatic void 4679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandpredicate_following(nir_cf_node *node, struct lower_returns_state *state) 4779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand{ 4879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_builder *b = &state->builder; 4979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand b->cursor = nir_after_cf_node_and_phis(node); 5079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 5179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (nir_cursors_equal(b->cursor, nir_after_cf_list(state->cf_list))) 5279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return; /* Nothing to predicate */ 5379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 5479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand assert(state->return_flag); 5579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 5679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_if *if_stmt = nir_if_create(b->shader); 5779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if_stmt->condition = nir_src_for_ssa(nir_load_var(b, state->return_flag)); 5879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_cf_node_insert(b->cursor, &if_stmt->cf_node); 5979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 6079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (state->loop) { 6179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand /* If we're inside of a loop, then all we need to do is insert a 6279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * conditional break. 6379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand */ 6479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_jump_instr *brk = 6579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_jump_instr_create(state->builder.shader, nir_jump_break); 6679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_instr_insert(nir_before_cf_list(&if_stmt->then_list), &brk->instr); 6779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } else { 6879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand /* Otherwise, we need to actually move everything into the else case 6979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * of the if statement. 7079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand */ 7179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_cf_list list; 7279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_cf_extract(&list, nir_after_cf_node(&if_stmt->cf_node), 7379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_after_cf_list(state->cf_list)); 7479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand assert(!exec_list_is_empty(&list.list)); 7579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_cf_reinsert(&list, nir_before_cf_list(&if_stmt->else_list)); 7679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } 7779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand} 7879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 7979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandstatic bool 8079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandlower_returns_in_loop(nir_loop *loop, struct lower_returns_state *state) 8179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand{ 8279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_loop *parent = state->loop; 8379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand state->loop = loop; 8479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand bool progress = lower_returns_in_cf_list(&loop->body, state); 8579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand state->loop = parent; 8679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 8779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand /* If the recursive call made progress, then there were returns inside 8879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * of the loop. These would have been lowered to breaks with the return 8979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * flag set to true. We need to predicate everything following the loop 9079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * on the return flag. 9179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand */ 92f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri if (progress) { 9379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand predicate_following(&loop->cf_node, state); 94f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri state->has_predicated_return = true; 95f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri } 9679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 9779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return progress; 9879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand} 9979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 10079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandstatic bool 10179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandlower_returns_in_if(nir_if *if_stmt, struct lower_returns_state *state) 10279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand{ 103f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri bool progress, then_progress, else_progress; 104f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri 105f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri bool has_predicated_return = state->has_predicated_return; 106f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri state->has_predicated_return = false; 10779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 108f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri then_progress = lower_returns_in_cf_list(&if_stmt->then_list, state); 109f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri else_progress = lower_returns_in_cf_list(&if_stmt->else_list, state); 110f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri progress = then_progress || else_progress; 11179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 11279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand /* If either of the recursive calls made progress, then there were 11379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * returns inside of the body of the if. If we're in a loop, then these 11479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * were lowered to breaks which automatically skip to the end of the 11579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * loop so we don't have to do anything. If we're not in a loop, then 11679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * all we know is that the return flag is set appropreately and that the 11779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * recursive calls ensured that nothing gets executed *inside* the if 11879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * after a return. In order to ensure nothing outside gets executed 11979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * after a return, we need to predicate everything following on the 12079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * return flag. 12179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand */ 122f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri if (progress && !state->loop) { 123f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri if (state->has_predicated_return) { 124f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri predicate_following(&if_stmt->cf_node, state); 125f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri } else { 126f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri /* If there are no nested returns we can just add the instructions to 127f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri * the end of the branch that doesn't have the return. 128f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri */ 129f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri nir_cf_list list; 130f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri nir_cf_extract(&list, nir_after_cf_node(&if_stmt->cf_node), 131f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri nir_after_cf_list(state->cf_list)); 132f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri 133f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri if (then_progress && else_progress) { 134f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri /* Both branches return so delete instructions following the if */ 135f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri nir_cf_delete(&list); 136f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri } else if (then_progress) { 137f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri nir_cf_reinsert(&list, nir_after_cf_list(&if_stmt->else_list)); 138f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri } else { 139f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri nir_cf_reinsert(&list, nir_after_cf_list(&if_stmt->then_list)); 140f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri } 141f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri } 142f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri } 143f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri 144f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri state->has_predicated_return = progress || has_predicated_return; 14579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 14679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return progress; 14779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand} 14879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 14979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandstatic bool 15079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandlower_returns_in_block(nir_block *block, struct lower_returns_state *state) 15179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand{ 15279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (block->predecessors->entries == 0 && 15379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand block != nir_start_block(state->builder.impl)) { 15479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand /* This block is unreachable. Delete it and everything after it. */ 15579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_cf_list list; 15679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_cf_extract(&list, nir_before_cf_node(&block->cf_node), 15779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_after_cf_list(state->cf_list)); 15879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 15979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (exec_list_is_empty(&list.list)) { 16079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand /* There's nothing here, which also means there's nothing in this 16179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * block so we have nothing to do. 16279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand */ 16379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return false; 16479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } else { 16579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_cf_delete(&list); 16679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return true; 16779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } 16879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } 16979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 17079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_instr *last_instr = nir_block_last_instr(block); 17179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (last_instr == NULL) 17279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return false; 17379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 17479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (last_instr->type != nir_instr_type_jump) 17579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return false; 17679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 17779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_jump_instr *jump = nir_instr_as_jump(last_instr); 17879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (jump->type != nir_jump_return) 17979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return false; 18079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 18179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_instr_remove(&jump->instr); 18279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 18379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_builder *b = &state->builder; 18479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 18579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand /* Set the return flag */ 18679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (state->return_flag == NULL) { 18779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand state->return_flag = 18879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_local_variable_create(b->impl, glsl_bool_type(), "return"); 18979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 190257aa5a1c4a2284ffd43759daa405fc135a40094Jason Ekstrand /* Initialize the variable to 0 */ 191257aa5a1c4a2284ffd43759daa405fc135a40094Jason Ekstrand b->cursor = nir_before_cf_list(&b->impl->body); 192257aa5a1c4a2284ffd43759daa405fc135a40094Jason Ekstrand nir_store_var(b, state->return_flag, nir_imm_int(b, NIR_FALSE), 1); 19379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } 194257aa5a1c4a2284ffd43759daa405fc135a40094Jason Ekstrand 195257aa5a1c4a2284ffd43759daa405fc135a40094Jason Ekstrand b->cursor = nir_after_block(block); 19679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_store_var(b, state->return_flag, nir_imm_int(b, NIR_TRUE), 1); 19779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 19879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (state->loop) { 19979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand /* We're in a loop; we need to break out of it. */ 20079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_jump(b, nir_jump_break); 20179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } else { 20279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand /* Not in a loop; we'll deal with predicating later*/ 20379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand assert(nir_cf_node_next(&block->cf_node) == NULL); 20479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } 20579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 20679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return true; 20779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand} 20879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 20979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandstatic bool 21079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandlower_returns_in_cf_list(struct exec_list *cf_list, 21179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand struct lower_returns_state *state) 21279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand{ 21379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand bool progress = false; 21479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 21579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand struct exec_list *parent_list = state->cf_list; 21679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand state->cf_list = cf_list; 21779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 21879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand /* We iterate over the list backwards because any given lower call may 21979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * take everything following the given CF node and predicate it. In 22079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * order to avoid recursion/iteration problems, we want everything after 22179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand * a given node to already be lowered before this happens. 22279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand */ 22379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand foreach_list_typed_reverse_safe(nir_cf_node, node, node, cf_list) { 22479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand switch (node->type) { 22579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand case nir_cf_node_block: 22679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (lower_returns_in_block(nir_cf_node_as_block(node), state)) 22779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand progress = true; 22879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand break; 22979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 23079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand case nir_cf_node_if: 23179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (lower_returns_in_if(nir_cf_node_as_if(node), state)) 23279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand progress = true; 23379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand break; 23479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 23579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand case nir_cf_node_loop: 23679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (lower_returns_in_loop(nir_cf_node_as_loop(node), state)) 23779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand progress = true; 23879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand break; 23979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 24079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand default: 24179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand unreachable("Invalid inner CF node type"); 24279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } 24379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } 24479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 24579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand state->cf_list = parent_list; 24679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 24779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return progress; 24879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand} 24979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 25079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandbool 25179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandnir_lower_returns_impl(nir_function_impl *impl) 25279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand{ 25379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand struct lower_returns_state state; 25479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 25579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand state.cf_list = &impl->body; 25679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand state.loop = NULL; 25779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand state.return_flag = NULL; 258f20ba7ad4476013a6a322a8d562f38bc6c4e2370Timothy Arceri state.has_predicated_return = false; 25979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_builder_init(&state.builder, impl); 26079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 26179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand bool progress = lower_returns_in_cf_list(&impl->body, &state); 26279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 26379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (progress) { 26479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_metadata_preserve(impl, nir_metadata_none); 26579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand nir_repair_ssa_impl(impl); 26679dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } 26779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 26879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return progress; 26979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand} 27079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 27179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandbool 27279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrandnir_lower_returns(nir_shader *shader) 27379dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand{ 27479dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand bool progress = false; 27579dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 2769464d8c49813aba77285e7465b96e92a91ed327cJason Ekstrand nir_foreach_function(function, shader) { 27779dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand if (function->impl) 27879dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand progress = nir_lower_returns_impl(function->impl) || progress; 27979dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand } 28079dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand 28179dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand return progress; 28279dec93ead6e3b95b1240a9d843d617a88ee9179Jason Ekstrand} 283