1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2014 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci * Authors:
24bf215546Sopenharmony_ci *    Connor Abbott (cwabbott0@gmail.com)
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci */
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "nir_control_flow_private.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci/**
31bf215546Sopenharmony_ci * \name Control flow modification
32bf215546Sopenharmony_ci *
33bf215546Sopenharmony_ci * These functions modify the control flow tree while keeping the control flow
34bf215546Sopenharmony_ci * graph up-to-date. The invariants respected are:
35bf215546Sopenharmony_ci * 1. Each then statement, else statement, or loop body must have at least one
36bf215546Sopenharmony_ci *    control flow node.
37bf215546Sopenharmony_ci * 2. Each if-statement and loop must have one basic block before it and one
38bf215546Sopenharmony_ci *    after.
39bf215546Sopenharmony_ci * 3. Two basic blocks cannot be directly next to each other.
40bf215546Sopenharmony_ci * 4. If a basic block has a jump instruction, there must be only one and it
41bf215546Sopenharmony_ci *    must be at the end of the block.
42bf215546Sopenharmony_ci *
43bf215546Sopenharmony_ci * The purpose of the second one is so that we have places to insert code during
44bf215546Sopenharmony_ci * GCM, as well as eliminating the possibility of critical edges.
45bf215546Sopenharmony_ci */
46bf215546Sopenharmony_ci/*@{*/
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_cistatic inline void
49bf215546Sopenharmony_ciblock_add_pred(nir_block *block, nir_block *pred)
50bf215546Sopenharmony_ci{
51bf215546Sopenharmony_ci   _mesa_set_add(block->predecessors, pred);
52bf215546Sopenharmony_ci}
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_cistatic inline void
55bf215546Sopenharmony_ciblock_remove_pred(nir_block *block, nir_block *pred)
56bf215546Sopenharmony_ci{
57bf215546Sopenharmony_ci   struct set_entry *entry = _mesa_set_search(block->predecessors, pred);
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   assert(entry);
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci   _mesa_set_remove(block->predecessors, entry);
62bf215546Sopenharmony_ci}
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_cistatic void
65bf215546Sopenharmony_cilink_blocks(nir_block *pred, nir_block *succ1, nir_block *succ2)
66bf215546Sopenharmony_ci{
67bf215546Sopenharmony_ci   pred->successors[0] = succ1;
68bf215546Sopenharmony_ci   if (succ1 != NULL)
69bf215546Sopenharmony_ci      block_add_pred(succ1, pred);
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   pred->successors[1] = succ2;
72bf215546Sopenharmony_ci   if (succ2 != NULL)
73bf215546Sopenharmony_ci      block_add_pred(succ2, pred);
74bf215546Sopenharmony_ci}
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_cistatic void
77bf215546Sopenharmony_ciunlink_blocks(nir_block *pred, nir_block *succ)
78bf215546Sopenharmony_ci{
79bf215546Sopenharmony_ci   if (pred->successors[0] == succ) {
80bf215546Sopenharmony_ci      pred->successors[0] = pred->successors[1];
81bf215546Sopenharmony_ci      pred->successors[1] = NULL;
82bf215546Sopenharmony_ci   } else {
83bf215546Sopenharmony_ci      assert(pred->successors[1] == succ);
84bf215546Sopenharmony_ci      pred->successors[1] = NULL;
85bf215546Sopenharmony_ci   }
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci   block_remove_pred(succ, pred);
88bf215546Sopenharmony_ci}
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_cistatic void
91bf215546Sopenharmony_ciunlink_block_successors(nir_block *block)
92bf215546Sopenharmony_ci{
93bf215546Sopenharmony_ci   if (block->successors[1] != NULL)
94bf215546Sopenharmony_ci      unlink_blocks(block, block->successors[1]);
95bf215546Sopenharmony_ci   if (block->successors[0] != NULL)
96bf215546Sopenharmony_ci      unlink_blocks(block, block->successors[0]);
97bf215546Sopenharmony_ci}
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_cistatic void
100bf215546Sopenharmony_cilink_non_block_to_block(nir_cf_node *node, nir_block *block)
101bf215546Sopenharmony_ci{
102bf215546Sopenharmony_ci   if (node->type == nir_cf_node_if) {
103bf215546Sopenharmony_ci      /*
104bf215546Sopenharmony_ci       * We're trying to link an if to a block after it; this just means linking
105bf215546Sopenharmony_ci       * the last block of the then and else branches.
106bf215546Sopenharmony_ci       */
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci      nir_if *if_stmt = nir_cf_node_as_if(node);
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci      nir_block *last_then_block = nir_if_last_then_block(if_stmt);
111bf215546Sopenharmony_ci      nir_block *last_else_block = nir_if_last_else_block(if_stmt);
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci      if (!nir_block_ends_in_jump(last_then_block)) {
114bf215546Sopenharmony_ci         unlink_block_successors(last_then_block);
115bf215546Sopenharmony_ci         link_blocks(last_then_block, block, NULL);
116bf215546Sopenharmony_ci      }
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci      if (!nir_block_ends_in_jump(last_else_block)) {
119bf215546Sopenharmony_ci         unlink_block_successors(last_else_block);
120bf215546Sopenharmony_ci         link_blocks(last_else_block, block, NULL);
121bf215546Sopenharmony_ci      }
122bf215546Sopenharmony_ci   } else {
123bf215546Sopenharmony_ci      assert(node->type == nir_cf_node_loop);
124bf215546Sopenharmony_ci   }
125bf215546Sopenharmony_ci}
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_cistatic void
128bf215546Sopenharmony_cilink_block_to_non_block(nir_block *block, nir_cf_node *node)
129bf215546Sopenharmony_ci{
130bf215546Sopenharmony_ci   if (node->type == nir_cf_node_if) {
131bf215546Sopenharmony_ci      /*
132bf215546Sopenharmony_ci       * We're trying to link a block to an if after it; this just means linking
133bf215546Sopenharmony_ci       * the block to the first block of the then and else branches.
134bf215546Sopenharmony_ci       */
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci      nir_if *if_stmt = nir_cf_node_as_if(node);
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci      nir_block *first_then_block = nir_if_first_then_block(if_stmt);
139bf215546Sopenharmony_ci      nir_block *first_else_block = nir_if_first_else_block(if_stmt);
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci      unlink_block_successors(block);
142bf215546Sopenharmony_ci      link_blocks(block, first_then_block, first_else_block);
143bf215546Sopenharmony_ci   } else if (node->type == nir_cf_node_loop) {
144bf215546Sopenharmony_ci      /*
145bf215546Sopenharmony_ci       * For similar reasons as the corresponding case in
146bf215546Sopenharmony_ci       * link_non_block_to_block(), don't worry about if the loop header has
147bf215546Sopenharmony_ci       * any predecessors that need to be unlinked.
148bf215546Sopenharmony_ci       */
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci      nir_loop *loop = nir_cf_node_as_loop(node);
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci      nir_block *loop_header_block = nir_loop_first_block(loop);
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci      unlink_block_successors(block);
155bf215546Sopenharmony_ci      link_blocks(block, loop_header_block, NULL);
156bf215546Sopenharmony_ci   }
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci}
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci/**
161bf215546Sopenharmony_ci * Replace a block's successor with a different one.
162bf215546Sopenharmony_ci */
163bf215546Sopenharmony_cistatic void
164bf215546Sopenharmony_cireplace_successor(nir_block *block, nir_block *old_succ, nir_block *new_succ)
165bf215546Sopenharmony_ci{
166bf215546Sopenharmony_ci   if (block->successors[0] == old_succ) {
167bf215546Sopenharmony_ci      block->successors[0] = new_succ;
168bf215546Sopenharmony_ci   } else {
169bf215546Sopenharmony_ci      assert(block->successors[1] == old_succ);
170bf215546Sopenharmony_ci      block->successors[1] = new_succ;
171bf215546Sopenharmony_ci   }
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   block_remove_pred(old_succ, block);
174bf215546Sopenharmony_ci   block_add_pred(new_succ, block);
175bf215546Sopenharmony_ci}
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci/**
178bf215546Sopenharmony_ci * Takes a basic block and inserts a new empty basic block before it, making its
179bf215546Sopenharmony_ci * predecessors point to the new block. This essentially splits the block into
180bf215546Sopenharmony_ci * an empty header and a body so that another non-block CF node can be inserted
181bf215546Sopenharmony_ci * between the two. Note that this does *not* link the two basic blocks, so
182bf215546Sopenharmony_ci * some kind of cleanup *must* be performed after this call.
183bf215546Sopenharmony_ci */
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_cistatic nir_block *
186bf215546Sopenharmony_cisplit_block_beginning(nir_block *block)
187bf215546Sopenharmony_ci{
188bf215546Sopenharmony_ci   nir_block *new_block = nir_block_create(ralloc_parent(block));
189bf215546Sopenharmony_ci   new_block->cf_node.parent = block->cf_node.parent;
190bf215546Sopenharmony_ci   exec_node_insert_node_before(&block->cf_node.node, &new_block->cf_node.node);
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci   set_foreach(block->predecessors, entry) {
193bf215546Sopenharmony_ci      nir_block *pred = (nir_block *) entry->key;
194bf215546Sopenharmony_ci      replace_successor(pred, block, new_block);
195bf215546Sopenharmony_ci   }
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci   /* Any phi nodes must stay part of the new block, or else their
198bf215546Sopenharmony_ci    * sources will be messed up.
199bf215546Sopenharmony_ci    */
200bf215546Sopenharmony_ci   nir_foreach_instr_safe(instr, block) {
201bf215546Sopenharmony_ci      if (instr->type != nir_instr_type_phi)
202bf215546Sopenharmony_ci         break;
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci      exec_node_remove(&instr->node);
205bf215546Sopenharmony_ci      instr->block = new_block;
206bf215546Sopenharmony_ci      exec_list_push_tail(&new_block->instr_list, &instr->node);
207bf215546Sopenharmony_ci   }
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_ci   return new_block;
210bf215546Sopenharmony_ci}
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_cistatic void
213bf215546Sopenharmony_cirewrite_phi_preds(nir_block *block, nir_block *old_pred, nir_block *new_pred)
214bf215546Sopenharmony_ci{
215bf215546Sopenharmony_ci   nir_foreach_instr_safe(instr, block) {
216bf215546Sopenharmony_ci      if (instr->type != nir_instr_type_phi)
217bf215546Sopenharmony_ci         break;
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci      nir_phi_instr *phi = nir_instr_as_phi(instr);
220bf215546Sopenharmony_ci      nir_foreach_phi_src(src, phi) {
221bf215546Sopenharmony_ci         if (src->pred == old_pred) {
222bf215546Sopenharmony_ci            src->pred = new_pred;
223bf215546Sopenharmony_ci            break;
224bf215546Sopenharmony_ci         }
225bf215546Sopenharmony_ci      }
226bf215546Sopenharmony_ci   }
227bf215546Sopenharmony_ci}
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_civoid
230bf215546Sopenharmony_cinir_insert_phi_undef(nir_block *block, nir_block *pred)
231bf215546Sopenharmony_ci{
232bf215546Sopenharmony_ci   nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node);
233bf215546Sopenharmony_ci   nir_foreach_instr(instr, block) {
234bf215546Sopenharmony_ci      if (instr->type != nir_instr_type_phi)
235bf215546Sopenharmony_ci         break;
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci      nir_phi_instr *phi = nir_instr_as_phi(instr);
238bf215546Sopenharmony_ci      nir_ssa_undef_instr *undef =
239bf215546Sopenharmony_ci         nir_ssa_undef_instr_create(impl->function->shader,
240bf215546Sopenharmony_ci                                    phi->dest.ssa.num_components,
241bf215546Sopenharmony_ci                                    phi->dest.ssa.bit_size);
242bf215546Sopenharmony_ci      nir_instr_insert_before_cf_list(&impl->body, &undef->instr);
243bf215546Sopenharmony_ci      nir_phi_src *src = nir_phi_instr_add_src(phi, pred, nir_src_for_ssa(&undef->def));
244bf215546Sopenharmony_ci      list_addtail(&src->src.use_link, &undef->def.uses);
245bf215546Sopenharmony_ci   }
246bf215546Sopenharmony_ci}
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci/**
249bf215546Sopenharmony_ci * Moves the successors of source to the successors of dest, leaving both
250bf215546Sopenharmony_ci * successors of source NULL.
251bf215546Sopenharmony_ci */
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_cistatic void
254bf215546Sopenharmony_cimove_successors(nir_block *source, nir_block *dest)
255bf215546Sopenharmony_ci{
256bf215546Sopenharmony_ci   nir_block *succ1 = source->successors[0];
257bf215546Sopenharmony_ci   nir_block *succ2 = source->successors[1];
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci   if (succ1) {
260bf215546Sopenharmony_ci      unlink_blocks(source, succ1);
261bf215546Sopenharmony_ci      rewrite_phi_preds(succ1, source, dest);
262bf215546Sopenharmony_ci   }
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci   if (succ2) {
265bf215546Sopenharmony_ci      unlink_blocks(source, succ2);
266bf215546Sopenharmony_ci      rewrite_phi_preds(succ2, source, dest);
267bf215546Sopenharmony_ci   }
268bf215546Sopenharmony_ci
269bf215546Sopenharmony_ci   unlink_block_successors(dest);
270bf215546Sopenharmony_ci   link_blocks(dest, succ1, succ2);
271bf215546Sopenharmony_ci}
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci/* Given a basic block with no successors that has been inserted into the
274bf215546Sopenharmony_ci * control flow tree, gives it the successors it would normally have assuming
275bf215546Sopenharmony_ci * it doesn't end in a jump instruction. Also inserts phi sources with undefs
276bf215546Sopenharmony_ci * if necessary.
277bf215546Sopenharmony_ci */
278bf215546Sopenharmony_cistatic void
279bf215546Sopenharmony_ciblock_add_normal_succs(nir_block *block)
280bf215546Sopenharmony_ci{
281bf215546Sopenharmony_ci   if (exec_node_is_tail_sentinel(block->cf_node.node.next)) {
282bf215546Sopenharmony_ci      nir_cf_node *parent = block->cf_node.parent;
283bf215546Sopenharmony_ci      if (parent->type == nir_cf_node_if) {
284bf215546Sopenharmony_ci         nir_cf_node *next = nir_cf_node_next(parent);
285bf215546Sopenharmony_ci         nir_block *next_block = nir_cf_node_as_block(next);
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci         link_blocks(block, next_block, NULL);
288bf215546Sopenharmony_ci      } else if (parent->type == nir_cf_node_loop) {
289bf215546Sopenharmony_ci         nir_loop *loop = nir_cf_node_as_loop(parent);
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci         nir_block *head_block = nir_loop_first_block(loop);
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci         link_blocks(block, head_block, NULL);
294bf215546Sopenharmony_ci         nir_insert_phi_undef(head_block, block);
295bf215546Sopenharmony_ci      } else {
296bf215546Sopenharmony_ci         nir_function_impl *impl = nir_cf_node_as_function(parent);
297bf215546Sopenharmony_ci         link_blocks(block, impl->end_block, NULL);
298bf215546Sopenharmony_ci      }
299bf215546Sopenharmony_ci   } else {
300bf215546Sopenharmony_ci      nir_cf_node *next = nir_cf_node_next(&block->cf_node);
301bf215546Sopenharmony_ci      if (next->type == nir_cf_node_if) {
302bf215546Sopenharmony_ci         nir_if *next_if = nir_cf_node_as_if(next);
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci         nir_block *first_then_block = nir_if_first_then_block(next_if);
305bf215546Sopenharmony_ci         nir_block *first_else_block = nir_if_first_else_block(next_if);
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci         link_blocks(block, first_then_block, first_else_block);
308bf215546Sopenharmony_ci      } else if (next->type == nir_cf_node_loop) {
309bf215546Sopenharmony_ci         nir_loop *next_loop = nir_cf_node_as_loop(next);
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci         nir_block *first_block = nir_loop_first_block(next_loop);
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci         link_blocks(block, first_block, NULL);
314bf215546Sopenharmony_ci         nir_insert_phi_undef(first_block, block);
315bf215546Sopenharmony_ci      }
316bf215546Sopenharmony_ci   }
317bf215546Sopenharmony_ci}
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_cistatic nir_block *
320bf215546Sopenharmony_cisplit_block_end(nir_block *block)
321bf215546Sopenharmony_ci{
322bf215546Sopenharmony_ci   nir_block *new_block = nir_block_create(ralloc_parent(block));
323bf215546Sopenharmony_ci   new_block->cf_node.parent = block->cf_node.parent;
324bf215546Sopenharmony_ci   exec_node_insert_after(&block->cf_node.node, &new_block->cf_node.node);
325bf215546Sopenharmony_ci
326bf215546Sopenharmony_ci   if (nir_block_ends_in_jump(block)) {
327bf215546Sopenharmony_ci      /* Figure out what successor block would've had if it didn't have a jump
328bf215546Sopenharmony_ci       * instruction, and make new_block have that successor.
329bf215546Sopenharmony_ci       */
330bf215546Sopenharmony_ci      block_add_normal_succs(new_block);
331bf215546Sopenharmony_ci   } else {
332bf215546Sopenharmony_ci      move_successors(block, new_block);
333bf215546Sopenharmony_ci   }
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci   return new_block;
336bf215546Sopenharmony_ci}
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_cistatic nir_block *
339bf215546Sopenharmony_cisplit_block_before_instr(nir_instr *instr)
340bf215546Sopenharmony_ci{
341bf215546Sopenharmony_ci   assert(instr->type != nir_instr_type_phi);
342bf215546Sopenharmony_ci   nir_block *new_block = split_block_beginning(instr->block);
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci   nir_foreach_instr_safe(cur_instr, instr->block) {
345bf215546Sopenharmony_ci      if (cur_instr == instr)
346bf215546Sopenharmony_ci         break;
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci      exec_node_remove(&cur_instr->node);
349bf215546Sopenharmony_ci      cur_instr->block = new_block;
350bf215546Sopenharmony_ci      exec_list_push_tail(&new_block->instr_list, &cur_instr->node);
351bf215546Sopenharmony_ci   }
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci   return new_block;
354bf215546Sopenharmony_ci}
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci/* Splits a basic block at the point specified by the cursor. The "before" and
357bf215546Sopenharmony_ci * "after" arguments are filled out with the blocks resulting from the split
358bf215546Sopenharmony_ci * if non-NULL. Note that the "beginning" of the block is actually interpreted
359bf215546Sopenharmony_ci * as before the first non-phi instruction, and it's illegal to split a block
360bf215546Sopenharmony_ci * before a phi instruction.
361bf215546Sopenharmony_ci */
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_cistatic void
364bf215546Sopenharmony_cisplit_block_cursor(nir_cursor cursor,
365bf215546Sopenharmony_ci                   nir_block **_before, nir_block **_after)
366bf215546Sopenharmony_ci{
367bf215546Sopenharmony_ci   nir_block *before, *after;
368bf215546Sopenharmony_ci   switch (cursor.option) {
369bf215546Sopenharmony_ci   case nir_cursor_before_block:
370bf215546Sopenharmony_ci      after = cursor.block;
371bf215546Sopenharmony_ci      before = split_block_beginning(cursor.block);
372bf215546Sopenharmony_ci      break;
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_ci   case nir_cursor_after_block:
375bf215546Sopenharmony_ci      before = cursor.block;
376bf215546Sopenharmony_ci      after = split_block_end(cursor.block);
377bf215546Sopenharmony_ci      break;
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_ci   case nir_cursor_before_instr:
380bf215546Sopenharmony_ci      after = cursor.instr->block;
381bf215546Sopenharmony_ci      before = split_block_before_instr(cursor.instr);
382bf215546Sopenharmony_ci      break;
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci   case nir_cursor_after_instr:
385bf215546Sopenharmony_ci      /* We lower this to split_block_before_instr() so that we can keep the
386bf215546Sopenharmony_ci       * after-a-jump-instr case contained to split_block_end().
387bf215546Sopenharmony_ci       */
388bf215546Sopenharmony_ci      if (nir_instr_is_last(cursor.instr)) {
389bf215546Sopenharmony_ci         before = cursor.instr->block;
390bf215546Sopenharmony_ci         after = split_block_end(cursor.instr->block);
391bf215546Sopenharmony_ci      } else {
392bf215546Sopenharmony_ci         after = cursor.instr->block;
393bf215546Sopenharmony_ci         before = split_block_before_instr(nir_instr_next(cursor.instr));
394bf215546Sopenharmony_ci      }
395bf215546Sopenharmony_ci      break;
396bf215546Sopenharmony_ci
397bf215546Sopenharmony_ci   default:
398bf215546Sopenharmony_ci      unreachable("not reached");
399bf215546Sopenharmony_ci   }
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_ci   if (_before)
402bf215546Sopenharmony_ci      *_before = before;
403bf215546Sopenharmony_ci   if (_after)
404bf215546Sopenharmony_ci      *_after = after;
405bf215546Sopenharmony_ci}
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci/**
408bf215546Sopenharmony_ci * Inserts a non-basic block between two basic blocks and links them together.
409bf215546Sopenharmony_ci */
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_cistatic void
412bf215546Sopenharmony_ciinsert_non_block(nir_block *before, nir_cf_node *node, nir_block *after)
413bf215546Sopenharmony_ci{
414bf215546Sopenharmony_ci   node->parent = before->cf_node.parent;
415bf215546Sopenharmony_ci   exec_node_insert_after(&before->cf_node.node, &node->node);
416bf215546Sopenharmony_ci   if (!nir_block_ends_in_jump(before))
417bf215546Sopenharmony_ci      link_block_to_non_block(before, node);
418bf215546Sopenharmony_ci   link_non_block_to_block(node, after);
419bf215546Sopenharmony_ci}
420bf215546Sopenharmony_ci
421bf215546Sopenharmony_ci/* walk up the control flow tree to find the innermost enclosed loop */
422bf215546Sopenharmony_cistatic nir_loop *
423bf215546Sopenharmony_cinearest_loop(nir_cf_node *node)
424bf215546Sopenharmony_ci{
425bf215546Sopenharmony_ci   while (node->type != nir_cf_node_loop) {
426bf215546Sopenharmony_ci      node = node->parent;
427bf215546Sopenharmony_ci   }
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci   return nir_cf_node_as_loop(node);
430bf215546Sopenharmony_ci}
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_cistatic void
433bf215546Sopenharmony_ciremove_phi_src(nir_block *block, nir_block *pred)
434bf215546Sopenharmony_ci{
435bf215546Sopenharmony_ci   nir_foreach_instr(instr, block) {
436bf215546Sopenharmony_ci      if (instr->type != nir_instr_type_phi)
437bf215546Sopenharmony_ci         break;
438bf215546Sopenharmony_ci
439bf215546Sopenharmony_ci      nir_phi_instr *phi = nir_instr_as_phi(instr);
440bf215546Sopenharmony_ci      nir_foreach_phi_src_safe(src, phi) {
441bf215546Sopenharmony_ci         if (src->pred == pred) {
442bf215546Sopenharmony_ci            list_del(&src->src.use_link);
443bf215546Sopenharmony_ci            exec_node_remove(&src->node);
444bf215546Sopenharmony_ci            free(src);
445bf215546Sopenharmony_ci         }
446bf215546Sopenharmony_ci      }
447bf215546Sopenharmony_ci   }
448bf215546Sopenharmony_ci}
449bf215546Sopenharmony_ci
450bf215546Sopenharmony_ci/*
451bf215546Sopenharmony_ci * update the CFG after a jump instruction has been added to the end of a block
452bf215546Sopenharmony_ci */
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_civoid
455bf215546Sopenharmony_cinir_handle_add_jump(nir_block *block)
456bf215546Sopenharmony_ci{
457bf215546Sopenharmony_ci   nir_instr *instr = nir_block_last_instr(block);
458bf215546Sopenharmony_ci   nir_jump_instr *jump_instr = nir_instr_as_jump(instr);
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_ci   if (block->successors[0])
461bf215546Sopenharmony_ci      remove_phi_src(block->successors[0], block);
462bf215546Sopenharmony_ci   if (block->successors[1])
463bf215546Sopenharmony_ci      remove_phi_src(block->successors[1], block);
464bf215546Sopenharmony_ci   unlink_block_successors(block);
465bf215546Sopenharmony_ci
466bf215546Sopenharmony_ci   nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node);
467bf215546Sopenharmony_ci   nir_metadata_preserve(impl, nir_metadata_none);
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ci   switch (jump_instr->type) {
470bf215546Sopenharmony_ci   case nir_jump_return:
471bf215546Sopenharmony_ci   case nir_jump_halt:
472bf215546Sopenharmony_ci      link_blocks(block, impl->end_block, NULL);
473bf215546Sopenharmony_ci      break;
474bf215546Sopenharmony_ci
475bf215546Sopenharmony_ci   case nir_jump_break: {
476bf215546Sopenharmony_ci      nir_loop *loop = nearest_loop(&block->cf_node);
477bf215546Sopenharmony_ci      nir_cf_node *after = nir_cf_node_next(&loop->cf_node);
478bf215546Sopenharmony_ci      nir_block *after_block = nir_cf_node_as_block(after);
479bf215546Sopenharmony_ci      link_blocks(block, after_block, NULL);
480bf215546Sopenharmony_ci      break;
481bf215546Sopenharmony_ci   }
482bf215546Sopenharmony_ci
483bf215546Sopenharmony_ci   case nir_jump_continue: {
484bf215546Sopenharmony_ci      nir_loop *loop = nearest_loop(&block->cf_node);
485bf215546Sopenharmony_ci      nir_block *first_block = nir_loop_first_block(loop);
486bf215546Sopenharmony_ci      link_blocks(block, first_block, NULL);
487bf215546Sopenharmony_ci      break;
488bf215546Sopenharmony_ci   }
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_ci   case nir_jump_goto:
491bf215546Sopenharmony_ci      link_blocks(block, jump_instr->target, NULL);
492bf215546Sopenharmony_ci      break;
493bf215546Sopenharmony_ci
494bf215546Sopenharmony_ci   case nir_jump_goto_if:
495bf215546Sopenharmony_ci      link_blocks(block, jump_instr->else_target, jump_instr->target);
496bf215546Sopenharmony_ci      break;
497bf215546Sopenharmony_ci
498bf215546Sopenharmony_ci   default:
499bf215546Sopenharmony_ci      unreachable("Invalid jump type");
500bf215546Sopenharmony_ci   }
501bf215546Sopenharmony_ci}
502bf215546Sopenharmony_ci
503bf215546Sopenharmony_ci/* Removes the successor of a block with a jump. Note that the jump to be
504bf215546Sopenharmony_ci * eliminated may be free-floating.
505bf215546Sopenharmony_ci */
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_cistatic void
508bf215546Sopenharmony_ciunlink_jump(nir_block *block, nir_jump_type type, bool add_normal_successors)
509bf215546Sopenharmony_ci{
510bf215546Sopenharmony_ci   if (block->successors[0])
511bf215546Sopenharmony_ci      remove_phi_src(block->successors[0], block);
512bf215546Sopenharmony_ci   if (block->successors[1])
513bf215546Sopenharmony_ci      remove_phi_src(block->successors[1], block);
514bf215546Sopenharmony_ci
515bf215546Sopenharmony_ci   unlink_block_successors(block);
516bf215546Sopenharmony_ci   if (add_normal_successors)
517bf215546Sopenharmony_ci      block_add_normal_succs(block);
518bf215546Sopenharmony_ci}
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_civoid
521bf215546Sopenharmony_cinir_handle_remove_jump(nir_block *block, nir_jump_type type)
522bf215546Sopenharmony_ci{
523bf215546Sopenharmony_ci   unlink_jump(block, type, true);
524bf215546Sopenharmony_ci
525bf215546Sopenharmony_ci   nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node);
526bf215546Sopenharmony_ci   nir_metadata_preserve(impl, nir_metadata_none);
527bf215546Sopenharmony_ci}
528bf215546Sopenharmony_ci
529bf215546Sopenharmony_cistatic void
530bf215546Sopenharmony_ciupdate_if_uses(nir_cf_node *node)
531bf215546Sopenharmony_ci{
532bf215546Sopenharmony_ci   if (node->type != nir_cf_node_if)
533bf215546Sopenharmony_ci      return;
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_ci   nir_if *if_stmt = nir_cf_node_as_if(node);
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci   if_stmt->condition.parent_if = if_stmt;
538bf215546Sopenharmony_ci   if (if_stmt->condition.is_ssa) {
539bf215546Sopenharmony_ci      list_addtail(&if_stmt->condition.use_link,
540bf215546Sopenharmony_ci                   &if_stmt->condition.ssa->if_uses);
541bf215546Sopenharmony_ci   } else {
542bf215546Sopenharmony_ci      list_addtail(&if_stmt->condition.use_link,
543bf215546Sopenharmony_ci                   &if_stmt->condition.reg.reg->if_uses);
544bf215546Sopenharmony_ci   }
545bf215546Sopenharmony_ci}
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci/**
548bf215546Sopenharmony_ci * Stitch two basic blocks together into one. The aggregate must have the same
549bf215546Sopenharmony_ci * predecessors as the first and the same successors as the second.
550bf215546Sopenharmony_ci *
551bf215546Sopenharmony_ci * Returns a cursor pointing at the end of the before block (i.e.m between the
552bf215546Sopenharmony_ci * two blocks) once stiched together.
553bf215546Sopenharmony_ci */
554bf215546Sopenharmony_ci
555bf215546Sopenharmony_cistatic nir_cursor
556bf215546Sopenharmony_cistitch_blocks(nir_block *before, nir_block *after)
557bf215546Sopenharmony_ci{
558bf215546Sopenharmony_ci   /*
559bf215546Sopenharmony_ci    * We move after into before, so we have to deal with up to 2 successors vs.
560bf215546Sopenharmony_ci    * possibly a large number of predecessors.
561bf215546Sopenharmony_ci    *
562bf215546Sopenharmony_ci    * TODO: special case when before is empty and after isn't?
563bf215546Sopenharmony_ci    */
564bf215546Sopenharmony_ci
565bf215546Sopenharmony_ci   if (nir_block_ends_in_jump(before)) {
566bf215546Sopenharmony_ci      assert(exec_list_is_empty(&after->instr_list));
567bf215546Sopenharmony_ci      if (after->successors[0])
568bf215546Sopenharmony_ci         remove_phi_src(after->successors[0], after);
569bf215546Sopenharmony_ci      if (after->successors[1])
570bf215546Sopenharmony_ci         remove_phi_src(after->successors[1], after);
571bf215546Sopenharmony_ci      unlink_block_successors(after);
572bf215546Sopenharmony_ci      exec_node_remove(&after->cf_node.node);
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci      return nir_after_block(before);
575bf215546Sopenharmony_ci   } else {
576bf215546Sopenharmony_ci      nir_instr *last_before_instr = nir_block_last_instr(before);
577bf215546Sopenharmony_ci
578bf215546Sopenharmony_ci      move_successors(after, before);
579bf215546Sopenharmony_ci
580bf215546Sopenharmony_ci      foreach_list_typed(nir_instr, instr, node, &after->instr_list) {
581bf215546Sopenharmony_ci         instr->block = before;
582bf215546Sopenharmony_ci      }
583bf215546Sopenharmony_ci
584bf215546Sopenharmony_ci      exec_list_append(&before->instr_list, &after->instr_list);
585bf215546Sopenharmony_ci      exec_node_remove(&after->cf_node.node);
586bf215546Sopenharmony_ci
587bf215546Sopenharmony_ci      return last_before_instr ? nir_after_instr(last_before_instr) :
588bf215546Sopenharmony_ci                                 nir_before_block(before);
589bf215546Sopenharmony_ci   }
590bf215546Sopenharmony_ci}
591bf215546Sopenharmony_ci
592bf215546Sopenharmony_civoid
593bf215546Sopenharmony_cinir_cf_node_insert(nir_cursor cursor, nir_cf_node *node)
594bf215546Sopenharmony_ci{
595bf215546Sopenharmony_ci   nir_block *before, *after;
596bf215546Sopenharmony_ci
597bf215546Sopenharmony_ci   split_block_cursor(cursor, &before, &after);
598bf215546Sopenharmony_ci
599bf215546Sopenharmony_ci   if (node->type == nir_cf_node_block) {
600bf215546Sopenharmony_ci      nir_block *block = nir_cf_node_as_block(node);
601bf215546Sopenharmony_ci      exec_node_insert_after(&before->cf_node.node, &block->cf_node.node);
602bf215546Sopenharmony_ci      block->cf_node.parent = before->cf_node.parent;
603bf215546Sopenharmony_ci      /* stitch_blocks() assumes that any block that ends with a jump has
604bf215546Sopenharmony_ci       * already been setup with the correct successors, so we need to set
605bf215546Sopenharmony_ci       * up jumps here as the block is being inserted.
606bf215546Sopenharmony_ci       */
607bf215546Sopenharmony_ci      if (nir_block_ends_in_jump(block))
608bf215546Sopenharmony_ci         nir_handle_add_jump(block);
609bf215546Sopenharmony_ci
610bf215546Sopenharmony_ci      stitch_blocks(block, after);
611bf215546Sopenharmony_ci      stitch_blocks(before, block);
612bf215546Sopenharmony_ci   } else {
613bf215546Sopenharmony_ci      update_if_uses(node);
614bf215546Sopenharmony_ci      insert_non_block(before, node, after);
615bf215546Sopenharmony_ci   }
616bf215546Sopenharmony_ci}
617bf215546Sopenharmony_ci
618bf215546Sopenharmony_cistatic bool
619bf215546Sopenharmony_cireplace_ssa_def_uses(nir_ssa_def *def, void *void_impl)
620bf215546Sopenharmony_ci{
621bf215546Sopenharmony_ci   nir_function_impl *impl = void_impl;
622bf215546Sopenharmony_ci
623bf215546Sopenharmony_ci   nir_ssa_undef_instr *undef =
624bf215546Sopenharmony_ci      nir_ssa_undef_instr_create(impl->function->shader,
625bf215546Sopenharmony_ci                                 def->num_components,
626bf215546Sopenharmony_ci                                 def->bit_size);
627bf215546Sopenharmony_ci   nir_instr_insert_before_cf_list(&impl->body, &undef->instr);
628bf215546Sopenharmony_ci   nir_ssa_def_rewrite_uses(def, &undef->def);
629bf215546Sopenharmony_ci   return true;
630bf215546Sopenharmony_ci}
631bf215546Sopenharmony_ci
632bf215546Sopenharmony_cistatic void
633bf215546Sopenharmony_cicleanup_cf_node(nir_cf_node *node, nir_function_impl *impl)
634bf215546Sopenharmony_ci{
635bf215546Sopenharmony_ci   switch (node->type) {
636bf215546Sopenharmony_ci   case nir_cf_node_block: {
637bf215546Sopenharmony_ci      nir_block *block = nir_cf_node_as_block(node);
638bf215546Sopenharmony_ci      /* We need to walk the instructions and clean up defs/uses */
639bf215546Sopenharmony_ci      nir_foreach_instr_safe(instr, block) {
640bf215546Sopenharmony_ci         if (instr->type == nir_instr_type_jump) {
641bf215546Sopenharmony_ci            nir_jump_instr *jump = nir_instr_as_jump(instr);
642bf215546Sopenharmony_ci            unlink_jump(block, jump->type, false);
643bf215546Sopenharmony_ci            if (jump->type == nir_jump_goto_if)
644bf215546Sopenharmony_ci               nir_instr_rewrite_src(instr, &jump->condition, NIR_SRC_INIT);
645bf215546Sopenharmony_ci         } else {
646bf215546Sopenharmony_ci            nir_foreach_ssa_def(instr, replace_ssa_def_uses, impl);
647bf215546Sopenharmony_ci            nir_instr_remove(instr);
648bf215546Sopenharmony_ci         }
649bf215546Sopenharmony_ci      }
650bf215546Sopenharmony_ci      break;
651bf215546Sopenharmony_ci   }
652bf215546Sopenharmony_ci
653bf215546Sopenharmony_ci   case nir_cf_node_if: {
654bf215546Sopenharmony_ci      nir_if *if_stmt = nir_cf_node_as_if(node);
655bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, child, node, &if_stmt->then_list)
656bf215546Sopenharmony_ci         cleanup_cf_node(child, impl);
657bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, child, node, &if_stmt->else_list)
658bf215546Sopenharmony_ci         cleanup_cf_node(child, impl);
659bf215546Sopenharmony_ci
660bf215546Sopenharmony_ci      list_del(&if_stmt->condition.use_link);
661bf215546Sopenharmony_ci      break;
662bf215546Sopenharmony_ci   }
663bf215546Sopenharmony_ci
664bf215546Sopenharmony_ci   case nir_cf_node_loop: {
665bf215546Sopenharmony_ci      nir_loop *loop = nir_cf_node_as_loop(node);
666bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, child, node, &loop->body)
667bf215546Sopenharmony_ci         cleanup_cf_node(child, impl);
668bf215546Sopenharmony_ci      break;
669bf215546Sopenharmony_ci   }
670bf215546Sopenharmony_ci   case nir_cf_node_function: {
671bf215546Sopenharmony_ci      nir_function_impl *impl = nir_cf_node_as_function(node);
672bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, child, node, &impl->body)
673bf215546Sopenharmony_ci         cleanup_cf_node(child, impl);
674bf215546Sopenharmony_ci      break;
675bf215546Sopenharmony_ci   }
676bf215546Sopenharmony_ci   default:
677bf215546Sopenharmony_ci      unreachable("Invalid CF node type");
678bf215546Sopenharmony_ci   }
679bf215546Sopenharmony_ci}
680bf215546Sopenharmony_ci
681bf215546Sopenharmony_ci/**
682bf215546Sopenharmony_ci * Extracts everything between two cursors.  Returns the cursor which is
683bf215546Sopenharmony_ci * equivalent to the old begin/end curosors.
684bf215546Sopenharmony_ci */
685bf215546Sopenharmony_cinir_cursor
686bf215546Sopenharmony_cinir_cf_extract(nir_cf_list *extracted, nir_cursor begin, nir_cursor end)
687bf215546Sopenharmony_ci{
688bf215546Sopenharmony_ci   nir_block *block_begin, *block_end, *block_before, *block_after;
689bf215546Sopenharmony_ci
690bf215546Sopenharmony_ci   if (nir_cursors_equal(begin, end)) {
691bf215546Sopenharmony_ci      exec_list_make_empty(&extracted->list);
692bf215546Sopenharmony_ci      extracted->impl = NULL; /* we shouldn't need this */
693bf215546Sopenharmony_ci      return begin;
694bf215546Sopenharmony_ci   }
695bf215546Sopenharmony_ci
696bf215546Sopenharmony_ci   split_block_cursor(begin, &block_before, &block_begin);
697bf215546Sopenharmony_ci
698bf215546Sopenharmony_ci   /* Splitting a block twice with two cursors created before either split is
699bf215546Sopenharmony_ci    * tricky and there are a couple of places it can go wrong if both cursors
700bf215546Sopenharmony_ci    * point to the same block.  One is if the second cursor is an block-based
701bf215546Sopenharmony_ci    * cursor and, thanks to the split above, it ends up pointing to the wrong
702bf215546Sopenharmony_ci    * block.  If it's a before_block cursor and it's in the same block as
703bf215546Sopenharmony_ci    * begin, then begin must also be a before_block cursor and it should be
704bf215546Sopenharmony_ci    * caught by the nir_cursors_equal check above and we won't get here.  If
705bf215546Sopenharmony_ci    * it's an after_block cursor, we need to re-adjust to ensure that it
706bf215546Sopenharmony_ci    * points to the second one of the split blocks, regardless of which it is.
707bf215546Sopenharmony_ci    */
708bf215546Sopenharmony_ci   if (end.option == nir_cursor_after_block && end.block == block_before)
709bf215546Sopenharmony_ci      end.block = block_begin;
710bf215546Sopenharmony_ci
711bf215546Sopenharmony_ci   split_block_cursor(end, &block_end, &block_after);
712bf215546Sopenharmony_ci
713bf215546Sopenharmony_ci   /* The second place this can all go wrong is that it could be that the
714bf215546Sopenharmony_ci    * second split places the original block after the new block in which case
715bf215546Sopenharmony_ci    * the block_begin pointer that we saved off above is pointing to the block
716bf215546Sopenharmony_ci    * at the end rather than the block in the middle like it's supposed to be.
717bf215546Sopenharmony_ci    * In this case, we have to re-adjust begin_block to point to the middle
718bf215546Sopenharmony_ci    * one.
719bf215546Sopenharmony_ci    */
720bf215546Sopenharmony_ci   if (block_begin == block_after)
721bf215546Sopenharmony_ci      block_begin = block_end;
722bf215546Sopenharmony_ci
723bf215546Sopenharmony_ci   extracted->impl = nir_cf_node_get_function(&block_begin->cf_node);
724bf215546Sopenharmony_ci   exec_list_make_empty(&extracted->list);
725bf215546Sopenharmony_ci
726bf215546Sopenharmony_ci   /* Dominance and other block-related information is toast. */
727bf215546Sopenharmony_ci   nir_metadata_preserve(extracted->impl, nir_metadata_none);
728bf215546Sopenharmony_ci
729bf215546Sopenharmony_ci   nir_cf_node *cf_node = &block_begin->cf_node;
730bf215546Sopenharmony_ci   nir_cf_node *cf_node_end = &block_end->cf_node;
731bf215546Sopenharmony_ci   while (true) {
732bf215546Sopenharmony_ci      nir_cf_node *next = nir_cf_node_next(cf_node);
733bf215546Sopenharmony_ci
734bf215546Sopenharmony_ci      exec_node_remove(&cf_node->node);
735bf215546Sopenharmony_ci      cf_node->parent = NULL;
736bf215546Sopenharmony_ci      exec_list_push_tail(&extracted->list, &cf_node->node);
737bf215546Sopenharmony_ci
738bf215546Sopenharmony_ci      if (cf_node == cf_node_end)
739bf215546Sopenharmony_ci         break;
740bf215546Sopenharmony_ci
741bf215546Sopenharmony_ci      cf_node = next;
742bf215546Sopenharmony_ci   }
743bf215546Sopenharmony_ci
744bf215546Sopenharmony_ci   return stitch_blocks(block_before, block_after);
745bf215546Sopenharmony_ci}
746bf215546Sopenharmony_ci
747bf215546Sopenharmony_cistatic void
748bf215546Sopenharmony_cirelink_jump_halt_cf_node(nir_cf_node *node, nir_block *end_block)
749bf215546Sopenharmony_ci{
750bf215546Sopenharmony_ci   switch (node->type) {
751bf215546Sopenharmony_ci   case nir_cf_node_block: {
752bf215546Sopenharmony_ci      nir_block *block = nir_cf_node_as_block(node);
753bf215546Sopenharmony_ci      nir_instr *last_instr = nir_block_last_instr(block);
754bf215546Sopenharmony_ci      if (last_instr == NULL || last_instr->type != nir_instr_type_jump)
755bf215546Sopenharmony_ci         break;
756bf215546Sopenharmony_ci
757bf215546Sopenharmony_ci      nir_jump_instr *jump = nir_instr_as_jump(last_instr);
758bf215546Sopenharmony_ci      /* We can't move a CF list from one function to another while we still
759bf215546Sopenharmony_ci       * have returns.
760bf215546Sopenharmony_ci       */
761bf215546Sopenharmony_ci      assert(jump->type != nir_jump_return);
762bf215546Sopenharmony_ci
763bf215546Sopenharmony_ci      if (jump->type == nir_jump_halt) {
764bf215546Sopenharmony_ci         unlink_block_successors(block);
765bf215546Sopenharmony_ci         link_blocks(block, end_block, NULL);
766bf215546Sopenharmony_ci      }
767bf215546Sopenharmony_ci      break;
768bf215546Sopenharmony_ci   }
769bf215546Sopenharmony_ci
770bf215546Sopenharmony_ci   case nir_cf_node_if: {
771bf215546Sopenharmony_ci      nir_if *if_stmt = nir_cf_node_as_if(node);
772bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, child, node, &if_stmt->then_list)
773bf215546Sopenharmony_ci         relink_jump_halt_cf_node(child, end_block);
774bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, child, node, &if_stmt->else_list)
775bf215546Sopenharmony_ci         relink_jump_halt_cf_node(child, end_block);
776bf215546Sopenharmony_ci      break;
777bf215546Sopenharmony_ci   }
778bf215546Sopenharmony_ci
779bf215546Sopenharmony_ci   case nir_cf_node_loop: {
780bf215546Sopenharmony_ci      nir_loop *loop = nir_cf_node_as_loop(node);
781bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, child, node, &loop->body)
782bf215546Sopenharmony_ci         relink_jump_halt_cf_node(child, end_block);
783bf215546Sopenharmony_ci      break;
784bf215546Sopenharmony_ci   }
785bf215546Sopenharmony_ci
786bf215546Sopenharmony_ci   case nir_cf_node_function:
787bf215546Sopenharmony_ci      unreachable("Cannot insert a function in a function");
788bf215546Sopenharmony_ci
789bf215546Sopenharmony_ci   default:
790bf215546Sopenharmony_ci      unreachable("Invalid CF node type");
791bf215546Sopenharmony_ci   }
792bf215546Sopenharmony_ci}
793bf215546Sopenharmony_ci
794bf215546Sopenharmony_ci/**
795bf215546Sopenharmony_ci * Inserts a list at a given cursor. Returns the cursor at the end of the
796bf215546Sopenharmony_ci * insertion (i.e., at the end of the instructions contained in cf_list).
797bf215546Sopenharmony_ci */
798bf215546Sopenharmony_cinir_cursor
799bf215546Sopenharmony_cinir_cf_reinsert(nir_cf_list *cf_list, nir_cursor cursor)
800bf215546Sopenharmony_ci{
801bf215546Sopenharmony_ci   nir_block *before, *after;
802bf215546Sopenharmony_ci
803bf215546Sopenharmony_ci   if (exec_list_is_empty(&cf_list->list))
804bf215546Sopenharmony_ci      return cursor;
805bf215546Sopenharmony_ci
806bf215546Sopenharmony_ci   nir_function_impl *cursor_impl =
807bf215546Sopenharmony_ci      nir_cf_node_get_function(&nir_cursor_current_block(cursor)->cf_node);
808bf215546Sopenharmony_ci   if (cf_list->impl != cursor_impl) {
809bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, node, node, &cf_list->list)
810bf215546Sopenharmony_ci         relink_jump_halt_cf_node(node, cursor_impl->end_block);
811bf215546Sopenharmony_ci   }
812bf215546Sopenharmony_ci
813bf215546Sopenharmony_ci   split_block_cursor(cursor, &before, &after);
814bf215546Sopenharmony_ci
815bf215546Sopenharmony_ci   foreach_list_typed_safe(nir_cf_node, node, node, &cf_list->list) {
816bf215546Sopenharmony_ci      exec_node_remove(&node->node);
817bf215546Sopenharmony_ci      node->parent = before->cf_node.parent;
818bf215546Sopenharmony_ci      exec_node_insert_node_before(&after->cf_node.node, &node->node);
819bf215546Sopenharmony_ci   }
820bf215546Sopenharmony_ci
821bf215546Sopenharmony_ci   stitch_blocks(before,
822bf215546Sopenharmony_ci                 nir_cf_node_as_block(nir_cf_node_next(&before->cf_node)));
823bf215546Sopenharmony_ci   return stitch_blocks(nir_cf_node_as_block(nir_cf_node_prev(&after->cf_node)),
824bf215546Sopenharmony_ci                        after);
825bf215546Sopenharmony_ci}
826bf215546Sopenharmony_ci
827bf215546Sopenharmony_civoid
828bf215546Sopenharmony_cinir_cf_delete(nir_cf_list *cf_list)
829bf215546Sopenharmony_ci{
830bf215546Sopenharmony_ci   foreach_list_typed(nir_cf_node, node, node, &cf_list->list) {
831bf215546Sopenharmony_ci      cleanup_cf_node(node, cf_list->impl);
832bf215546Sopenharmony_ci   }
833bf215546Sopenharmony_ci}
834