1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2015 Thomas Helland
3bf215546Sopenharmony_ci * Copyright © 2019 Valve Corporation
4bf215546Sopenharmony_ci *
5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
8bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
10bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
11bf215546Sopenharmony_ci *
12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
14bf215546Sopenharmony_ci * Software.
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22bf215546Sopenharmony_ci * IN THE SOFTWARE.
23bf215546Sopenharmony_ci */
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci/*
26bf215546Sopenharmony_ci * This pass converts the ssa-graph into "Loop Closed SSA form". This is
27bf215546Sopenharmony_ci * done by placing phi nodes at the exits of the loop for all values
28bf215546Sopenharmony_ci * that are used outside the loop. The result is it transforms:
29bf215546Sopenharmony_ci *
30bf215546Sopenharmony_ci * loop {                    ->      loop {
31bf215546Sopenharmony_ci *    ssa2 = ....            ->          ssa2 = ...
32bf215546Sopenharmony_ci *    if (cond)              ->          if (cond)
33bf215546Sopenharmony_ci *       break;              ->             break;
34bf215546Sopenharmony_ci *    ssa3 = ssa2 * ssa4     ->          ssa3 = ssa2 * ssa4
35bf215546Sopenharmony_ci * }                         ->       }
36bf215546Sopenharmony_ci * ssa6 = ssa2 + 4           ->       ssa5 = phi(ssa2)
37bf215546Sopenharmony_ci *                                    ssa6 = ssa5 + 4
38bf215546Sopenharmony_ci */
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci#include "nir.h"
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_citypedef struct {
43bf215546Sopenharmony_ci   /* The nir_shader we are transforming */
44bf215546Sopenharmony_ci   nir_shader *shader;
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci   /* The loop we store information for */
47bf215546Sopenharmony_ci   nir_loop *loop;
48bf215546Sopenharmony_ci   nir_block *block_after_loop;
49bf215546Sopenharmony_ci   nir_block **exit_blocks;
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci   /* Whether to skip loop invariant variables */
52bf215546Sopenharmony_ci   bool skip_invariants;
53bf215546Sopenharmony_ci   bool skip_bool_invariants;
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci   bool progress;
56bf215546Sopenharmony_ci} lcssa_state;
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_cistatic bool
59bf215546Sopenharmony_ciis_if_use_inside_loop(nir_src *use, nir_loop *loop)
60bf215546Sopenharmony_ci{
61bf215546Sopenharmony_ci   nir_block *block_before_loop =
62bf215546Sopenharmony_ci      nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node));
63bf215546Sopenharmony_ci   nir_block *block_after_loop =
64bf215546Sopenharmony_ci      nir_cf_node_as_block(nir_cf_node_next(&loop->cf_node));
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   nir_block *prev_block =
67bf215546Sopenharmony_ci      nir_cf_node_as_block(nir_cf_node_prev(&use->parent_if->cf_node));
68bf215546Sopenharmony_ci   if (prev_block->index <= block_before_loop->index ||
69bf215546Sopenharmony_ci       prev_block->index >= block_after_loop->index) {
70bf215546Sopenharmony_ci      return false;
71bf215546Sopenharmony_ci   }
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci   return true;
74bf215546Sopenharmony_ci}
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_cistatic bool
77bf215546Sopenharmony_ciis_use_inside_loop(nir_src *use, nir_loop *loop)
78bf215546Sopenharmony_ci{
79bf215546Sopenharmony_ci   nir_block *block_before_loop =
80bf215546Sopenharmony_ci      nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node));
81bf215546Sopenharmony_ci   nir_block *block_after_loop =
82bf215546Sopenharmony_ci      nir_cf_node_as_block(nir_cf_node_next(&loop->cf_node));
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   if (use->parent_instr->block->index <= block_before_loop->index ||
85bf215546Sopenharmony_ci       use->parent_instr->block->index >= block_after_loop->index) {
86bf215546Sopenharmony_ci      return false;
87bf215546Sopenharmony_ci   }
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   return true;
90bf215546Sopenharmony_ci}
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_cistatic bool
93bf215546Sopenharmony_ciis_defined_before_loop(nir_ssa_def *def, nir_loop *loop)
94bf215546Sopenharmony_ci{
95bf215546Sopenharmony_ci   nir_instr *instr = def->parent_instr;
96bf215546Sopenharmony_ci   nir_block *block_before_loop =
97bf215546Sopenharmony_ci      nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node));
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci   return instr->block->index <= block_before_loop->index;
100bf215546Sopenharmony_ci}
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_citypedef enum instr_invariance {
103bf215546Sopenharmony_ci   undefined = 0,
104bf215546Sopenharmony_ci   invariant,
105bf215546Sopenharmony_ci   not_invariant,
106bf215546Sopenharmony_ci} instr_invariance;
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_cistatic instr_invariance
109bf215546Sopenharmony_ciinstr_is_invariant(nir_instr *instr, nir_loop *loop);
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_cistatic bool
112bf215546Sopenharmony_cidef_is_invariant(nir_ssa_def *def, nir_loop *loop)
113bf215546Sopenharmony_ci{
114bf215546Sopenharmony_ci   if (is_defined_before_loop(def, loop))
115bf215546Sopenharmony_ci      return invariant;
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   if (def->parent_instr->pass_flags == undefined)
118bf215546Sopenharmony_ci      def->parent_instr->pass_flags = instr_is_invariant(def->parent_instr, loop);
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   return def->parent_instr->pass_flags == invariant;
121bf215546Sopenharmony_ci}
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_cistatic bool
124bf215546Sopenharmony_cisrc_is_invariant(nir_src *src, void *state)
125bf215546Sopenharmony_ci{
126bf215546Sopenharmony_ci   assert(src->is_ssa);
127bf215546Sopenharmony_ci   return def_is_invariant(src->ssa, (nir_loop *)state);
128bf215546Sopenharmony_ci}
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_cistatic instr_invariance
131bf215546Sopenharmony_ciphi_is_invariant(nir_phi_instr *instr, nir_loop *loop)
132bf215546Sopenharmony_ci{
133bf215546Sopenharmony_ci   /* Base case: it's a phi at the loop header
134bf215546Sopenharmony_ci    * Loop-header phis are updated in each loop iteration with
135bf215546Sopenharmony_ci    * the loop-carried value, and thus control-flow dependent
136bf215546Sopenharmony_ci    * on the loop itself.
137bf215546Sopenharmony_ci    */
138bf215546Sopenharmony_ci   if (instr->instr.block == nir_loop_first_block(loop))
139bf215546Sopenharmony_ci      return not_invariant;
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   nir_foreach_phi_src(src, instr) {
142bf215546Sopenharmony_ci      if (!src_is_invariant(&src->src, loop))
143bf215546Sopenharmony_ci         return not_invariant;
144bf215546Sopenharmony_ci   }
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci   /* All loop header- and LCSSA-phis should be handled by this point. */
147bf215546Sopenharmony_ci   nir_cf_node *prev = nir_cf_node_prev(&instr->instr.block->cf_node);
148bf215546Sopenharmony_ci   assert(prev && prev->type == nir_cf_node_if);
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci   /* Invariance of phis after if-nodes also depends on the invariance
151bf215546Sopenharmony_ci    * of the branch condition.
152bf215546Sopenharmony_ci    */
153bf215546Sopenharmony_ci   nir_if *if_node = nir_cf_node_as_if(prev);
154bf215546Sopenharmony_ci   if (!def_is_invariant(if_node->condition.ssa, loop))
155bf215546Sopenharmony_ci      return not_invariant;
156bf215546Sopenharmony_ci
157bf215546Sopenharmony_ci   return invariant;
158bf215546Sopenharmony_ci}
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci/* An instruction is said to be loop-invariant if it
162bf215546Sopenharmony_ci * - has no sideeffects and
163bf215546Sopenharmony_ci * - solely depends on variables defined outside of the loop or
164bf215546Sopenharmony_ci *   by other invariant instructions
165bf215546Sopenharmony_ci */
166bf215546Sopenharmony_cistatic instr_invariance
167bf215546Sopenharmony_ciinstr_is_invariant(nir_instr *instr, nir_loop *loop)
168bf215546Sopenharmony_ci{
169bf215546Sopenharmony_ci   assert(instr->pass_flags == undefined);
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   switch (instr->type) {
172bf215546Sopenharmony_ci   case nir_instr_type_load_const:
173bf215546Sopenharmony_ci   case nir_instr_type_ssa_undef:
174bf215546Sopenharmony_ci      return invariant;
175bf215546Sopenharmony_ci   case nir_instr_type_call:
176bf215546Sopenharmony_ci      return not_invariant;
177bf215546Sopenharmony_ci   case nir_instr_type_phi:
178bf215546Sopenharmony_ci      return phi_is_invariant(nir_instr_as_phi(instr), loop);
179bf215546Sopenharmony_ci   case nir_instr_type_intrinsic: {
180bf215546Sopenharmony_ci      nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(instr);
181bf215546Sopenharmony_ci      if (!(nir_intrinsic_infos[intrinsic->intrinsic].flags & NIR_INTRINSIC_CAN_REORDER))
182bf215546Sopenharmony_ci         return not_invariant;
183bf215546Sopenharmony_ci   }
184bf215546Sopenharmony_ci   FALLTHROUGH;
185bf215546Sopenharmony_ci   default:
186bf215546Sopenharmony_ci      return nir_foreach_src(instr, src_is_invariant, loop) ? invariant : not_invariant;
187bf215546Sopenharmony_ci   }
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   return invariant;
190bf215546Sopenharmony_ci}
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_cistatic bool
193bf215546Sopenharmony_ciconvert_loop_exit_for_ssa(nir_ssa_def *def, void *void_state)
194bf215546Sopenharmony_ci{
195bf215546Sopenharmony_ci   lcssa_state *state = void_state;
196bf215546Sopenharmony_ci   bool all_uses_inside_loop = true;
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   /* Don't create LCSSA-Phis for loop-invariant variables */
199bf215546Sopenharmony_ci   if (state->skip_invariants &&
200bf215546Sopenharmony_ci       (def->bit_size != 1 || state->skip_bool_invariants)) {
201bf215546Sopenharmony_ci      assert(def->parent_instr->pass_flags != undefined);
202bf215546Sopenharmony_ci      if (def->parent_instr->pass_flags == invariant)
203bf215546Sopenharmony_ci         return true;
204bf215546Sopenharmony_ci   }
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   nir_foreach_use(use, def) {
207bf215546Sopenharmony_ci      if (use->parent_instr->type == nir_instr_type_phi &&
208bf215546Sopenharmony_ci          use->parent_instr->block == state->block_after_loop) {
209bf215546Sopenharmony_ci         continue;
210bf215546Sopenharmony_ci      }
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci      if (!is_use_inside_loop(use, state->loop)) {
213bf215546Sopenharmony_ci         all_uses_inside_loop = false;
214bf215546Sopenharmony_ci      }
215bf215546Sopenharmony_ci   }
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci   nir_foreach_if_use(use, def) {
218bf215546Sopenharmony_ci      if (!is_if_use_inside_loop(use, state->loop)) {
219bf215546Sopenharmony_ci         all_uses_inside_loop = false;
220bf215546Sopenharmony_ci      }
221bf215546Sopenharmony_ci   }
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci   /* There where no sources that had defs outside the loop */
224bf215546Sopenharmony_ci   if (all_uses_inside_loop)
225bf215546Sopenharmony_ci      return true;
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci   /* Initialize a phi-instruction */
228bf215546Sopenharmony_ci   nir_phi_instr *phi = nir_phi_instr_create(state->shader);
229bf215546Sopenharmony_ci   nir_ssa_dest_init(&phi->instr, &phi->dest,
230bf215546Sopenharmony_ci                     def->num_components, def->bit_size, "LCSSA-phi");
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   /* Create a phi node with as many sources pointing to the same ssa_def as
233bf215546Sopenharmony_ci    * the block has predecessors.
234bf215546Sopenharmony_ci    */
235bf215546Sopenharmony_ci   uint32_t num_exits = state->block_after_loop->predecessors->entries;
236bf215546Sopenharmony_ci   for (uint32_t i = 0; i < num_exits; i++) {
237bf215546Sopenharmony_ci      nir_phi_instr_add_src(phi, state->exit_blocks[i], nir_src_for_ssa(def));
238bf215546Sopenharmony_ci   }
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci   nir_instr_insert_before_block(state->block_after_loop, &phi->instr);
241bf215546Sopenharmony_ci   nir_ssa_def *dest = &phi->dest.ssa;
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   /* deref instructions need a cast after the phi */
244bf215546Sopenharmony_ci   if (def->parent_instr->type == nir_instr_type_deref) {
245bf215546Sopenharmony_ci      nir_deref_instr *cast =
246bf215546Sopenharmony_ci         nir_deref_instr_create(state->shader, nir_deref_type_cast);
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci      nir_deref_instr *instr = nir_instr_as_deref(def->parent_instr);
249bf215546Sopenharmony_ci      cast->modes = instr->modes;
250bf215546Sopenharmony_ci      cast->type = instr->type;
251bf215546Sopenharmony_ci      cast->parent = nir_src_for_ssa(&phi->dest.ssa);
252bf215546Sopenharmony_ci      cast->cast.ptr_stride = nir_deref_instr_array_stride(instr);
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci      nir_ssa_dest_init(&cast->instr, &cast->dest,
255bf215546Sopenharmony_ci                        phi->dest.ssa.num_components,
256bf215546Sopenharmony_ci                        phi->dest.ssa.bit_size, NULL);
257bf215546Sopenharmony_ci      nir_instr_insert(nir_after_phis(state->block_after_loop), &cast->instr);
258bf215546Sopenharmony_ci      dest = &cast->dest.ssa;
259bf215546Sopenharmony_ci   }
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci   /* Run through all uses and rewrite those outside the loop to point to
262bf215546Sopenharmony_ci    * the phi instead of pointing to the ssa-def.
263bf215546Sopenharmony_ci    */
264bf215546Sopenharmony_ci   nir_foreach_use_safe(use, def) {
265bf215546Sopenharmony_ci      if (use->parent_instr->type == nir_instr_type_phi &&
266bf215546Sopenharmony_ci          state->block_after_loop == use->parent_instr->block) {
267bf215546Sopenharmony_ci         continue;
268bf215546Sopenharmony_ci      }
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci      if (!is_use_inside_loop(use, state->loop)) {
271bf215546Sopenharmony_ci         nir_instr_rewrite_src(use->parent_instr, use, nir_src_for_ssa(dest));
272bf215546Sopenharmony_ci      }
273bf215546Sopenharmony_ci   }
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ci   nir_foreach_if_use_safe(use, def) {
276bf215546Sopenharmony_ci      if (!is_if_use_inside_loop(use, state->loop)) {
277bf215546Sopenharmony_ci         nir_if_rewrite_condition(use->parent_if, nir_src_for_ssa(dest));
278bf215546Sopenharmony_ci      }
279bf215546Sopenharmony_ci   }
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   state->progress = true;
282bf215546Sopenharmony_ci   return true;
283bf215546Sopenharmony_ci}
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_cistatic void
286bf215546Sopenharmony_cisetup_loop_state(lcssa_state *state, nir_loop *loop)
287bf215546Sopenharmony_ci{
288bf215546Sopenharmony_ci   state->loop = loop;
289bf215546Sopenharmony_ci   state->block_after_loop =
290bf215546Sopenharmony_ci      nir_cf_node_as_block(nir_cf_node_next(&loop->cf_node));
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   ralloc_free(state->exit_blocks);
293bf215546Sopenharmony_ci   state->exit_blocks = nir_block_get_predecessors_sorted(state->block_after_loop, state);
294bf215546Sopenharmony_ci}
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_cistatic void
297bf215546Sopenharmony_ciconvert_to_lcssa(nir_cf_node *cf_node, lcssa_state *state)
298bf215546Sopenharmony_ci{
299bf215546Sopenharmony_ci   switch (cf_node->type) {
300bf215546Sopenharmony_ci   case nir_cf_node_block:
301bf215546Sopenharmony_ci      return;
302bf215546Sopenharmony_ci   case nir_cf_node_if: {
303bf215546Sopenharmony_ci      nir_if *if_stmt = nir_cf_node_as_if(cf_node);
304bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, nested_node, node, &if_stmt->then_list)
305bf215546Sopenharmony_ci         convert_to_lcssa(nested_node, state);
306bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, nested_node, node, &if_stmt->else_list)
307bf215546Sopenharmony_ci         convert_to_lcssa(nested_node, state);
308bf215546Sopenharmony_ci      return;
309bf215546Sopenharmony_ci   }
310bf215546Sopenharmony_ci   case nir_cf_node_loop: {
311bf215546Sopenharmony_ci      if (state->skip_invariants) {
312bf215546Sopenharmony_ci         nir_foreach_block_in_cf_node(block, cf_node) {
313bf215546Sopenharmony_ci            nir_foreach_instr(instr, block)
314bf215546Sopenharmony_ci               instr->pass_flags = undefined;
315bf215546Sopenharmony_ci         }
316bf215546Sopenharmony_ci      }
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci      /* first, convert inner loops */
319bf215546Sopenharmony_ci      nir_loop *loop = nir_cf_node_as_loop(cf_node);
320bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, nested_node, node, &loop->body)
321bf215546Sopenharmony_ci         convert_to_lcssa(nested_node, state);
322bf215546Sopenharmony_ci
323bf215546Sopenharmony_ci      setup_loop_state(state, loop);
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_ci      /* mark loop-invariant instructions */
326bf215546Sopenharmony_ci      if (state->skip_invariants) {
327bf215546Sopenharmony_ci         /* Without a loop all instructions are invariant.
328bf215546Sopenharmony_ci          * For outer loops, multiple breaks can still create phis.
329bf215546Sopenharmony_ci          * The variance then depends on all (nested) break conditions.
330bf215546Sopenharmony_ci          * We don't consider this, but assume all not_invariant.
331bf215546Sopenharmony_ci          */
332bf215546Sopenharmony_ci         if (nir_loop_first_block(loop)->predecessors->entries == 1)
333bf215546Sopenharmony_ci            goto end;
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci         nir_foreach_block_in_cf_node(block, cf_node) {
336bf215546Sopenharmony_ci            nir_foreach_instr(instr, block) {
337bf215546Sopenharmony_ci               if (instr->pass_flags == undefined)
338bf215546Sopenharmony_ci                  instr->pass_flags = instr_is_invariant(instr, nir_cf_node_as_loop(cf_node));
339bf215546Sopenharmony_ci            }
340bf215546Sopenharmony_ci         }
341bf215546Sopenharmony_ci      }
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci      nir_foreach_block_in_cf_node(block, cf_node) {
344bf215546Sopenharmony_ci         nir_foreach_instr(instr, block) {
345bf215546Sopenharmony_ci            nir_foreach_ssa_def(instr, convert_loop_exit_for_ssa, state);
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci            /* for outer loops, invariant instructions can be variant */
348bf215546Sopenharmony_ci            if (state->skip_invariants && instr->pass_flags == invariant)
349bf215546Sopenharmony_ci               instr->pass_flags = undefined;
350bf215546Sopenharmony_ci         }
351bf215546Sopenharmony_ci      }
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ciend:
354bf215546Sopenharmony_ci      /* For outer loops, the LCSSA-phi should be considered not invariant */
355bf215546Sopenharmony_ci      if (state->skip_invariants) {
356bf215546Sopenharmony_ci         nir_foreach_instr(instr, state->block_after_loop) {
357bf215546Sopenharmony_ci            if (instr->type == nir_instr_type_phi)
358bf215546Sopenharmony_ci               instr->pass_flags = not_invariant;
359bf215546Sopenharmony_ci            else
360bf215546Sopenharmony_ci               break;
361bf215546Sopenharmony_ci         }
362bf215546Sopenharmony_ci      }
363bf215546Sopenharmony_ci      return;
364bf215546Sopenharmony_ci   }
365bf215546Sopenharmony_ci   default:
366bf215546Sopenharmony_ci      unreachable("unknown cf node type");
367bf215546Sopenharmony_ci   }
368bf215546Sopenharmony_ci}
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_civoid
371bf215546Sopenharmony_cinir_convert_loop_to_lcssa(nir_loop *loop)
372bf215546Sopenharmony_ci{
373bf215546Sopenharmony_ci   nir_function_impl *impl = nir_cf_node_get_function(&loop->cf_node);
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci   nir_metadata_require(impl, nir_metadata_block_index);
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci   lcssa_state *state = rzalloc(NULL, lcssa_state);
378bf215546Sopenharmony_ci   setup_loop_state(state, loop);
379bf215546Sopenharmony_ci   state->shader = impl->function->shader;
380bf215546Sopenharmony_ci   state->skip_invariants = false;
381bf215546Sopenharmony_ci   state->skip_bool_invariants = false;
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci   nir_foreach_block_in_cf_node (block, &loop->cf_node) {
384bf215546Sopenharmony_ci      nir_foreach_instr(instr, block)
385bf215546Sopenharmony_ci         nir_foreach_ssa_def(instr, convert_loop_exit_for_ssa, state);
386bf215546Sopenharmony_ci   }
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_ci   ralloc_free(state);
389bf215546Sopenharmony_ci}
390bf215546Sopenharmony_ci
391bf215546Sopenharmony_cibool
392bf215546Sopenharmony_cinir_convert_to_lcssa(nir_shader *shader, bool skip_invariants, bool skip_bool_invariants)
393bf215546Sopenharmony_ci{
394bf215546Sopenharmony_ci   bool progress = false;
395bf215546Sopenharmony_ci   lcssa_state *state = rzalloc(NULL, lcssa_state);
396bf215546Sopenharmony_ci   state->shader = shader;
397bf215546Sopenharmony_ci   state->skip_invariants = skip_invariants;
398bf215546Sopenharmony_ci   state->skip_bool_invariants = skip_bool_invariants;
399bf215546Sopenharmony_ci
400bf215546Sopenharmony_ci   nir_foreach_function(function, shader) {
401bf215546Sopenharmony_ci      if (function->impl == NULL)
402bf215546Sopenharmony_ci         continue;
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci      state->progress = false;
405bf215546Sopenharmony_ci      nir_metadata_require(function->impl, nir_metadata_block_index);
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci      foreach_list_typed(nir_cf_node, node, node, &function->impl->body)
408bf215546Sopenharmony_ci         convert_to_lcssa(node, state);
409bf215546Sopenharmony_ci
410bf215546Sopenharmony_ci      if (state->progress) {
411bf215546Sopenharmony_ci         progress = true;
412bf215546Sopenharmony_ci         nir_metadata_preserve(function->impl, nir_metadata_block_index |
413bf215546Sopenharmony_ci                                               nir_metadata_dominance);
414bf215546Sopenharmony_ci      } else {
415bf215546Sopenharmony_ci         nir_metadata_preserve(function->impl, nir_metadata_all);
416bf215546Sopenharmony_ci      }
417bf215546Sopenharmony_ci   }
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci   ralloc_free(state);
420bf215546Sopenharmony_ci   return progress;
421bf215546Sopenharmony_ci}
422bf215546Sopenharmony_ci
423