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