nir: add if opt opt_if_loop_last_continue()
[mesa.git] / src / compiler / nir / nir_opt_if.c
1 /*
2 * Copyright © 2016 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "nir.h"
25 #include "nir/nir_builder.h"
26 #include "nir_constant_expressions.h"
27 #include "nir_control_flow.h"
28 #include "nir_loop_analyze.h"
29
30 /**
31 * Gets the single block that jumps back to the loop header. Already assumes
32 * there is exactly one such block.
33 */
34 static nir_block*
35 find_continue_block(nir_loop *loop)
36 {
37 nir_block *header_block = nir_loop_first_block(loop);
38 nir_block *prev_block =
39 nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node));
40
41 assert(header_block->predecessors->entries == 2);
42
43 set_foreach(header_block->predecessors, pred_entry) {
44 if (pred_entry->key != prev_block)
45 return (nir_block*)pred_entry->key;
46 }
47
48 unreachable("Continue block not found!");
49 }
50
51 /**
52 * This optimization detects if statements at the tops of loops where the
53 * condition is a phi node of two constants and moves half of the if to above
54 * the loop and the other half of the if to the end of the loop. A simple for
55 * loop "for (int i = 0; i < 4; i++)", when run through the SPIR-V front-end,
56 * ends up looking something like this:
57 *
58 * vec1 32 ssa_0 = load_const (0x00000000)
59 * vec1 32 ssa_1 = load_const (0xffffffff)
60 * loop {
61 * block block_1:
62 * vec1 32 ssa_2 = phi block_0: ssa_0, block_7: ssa_5
63 * vec1 32 ssa_3 = phi block_0: ssa_0, block_7: ssa_1
64 * if ssa_2 {
65 * block block_2:
66 * vec1 32 ssa_4 = load_const (0x00000001)
67 * vec1 32 ssa_5 = iadd ssa_2, ssa_4
68 * } else {
69 * block block_3:
70 * }
71 * block block_4:
72 * vec1 32 ssa_6 = load_const (0x00000004)
73 * vec1 32 ssa_7 = ilt ssa_5, ssa_6
74 * if ssa_7 {
75 * block block_5:
76 * } else {
77 * block block_6:
78 * break
79 * }
80 * block block_7:
81 * }
82 *
83 * This turns it into something like this:
84 *
85 * // Stuff from block 1
86 * // Stuff from block 3
87 * loop {
88 * block block_1:
89 * vec1 32 ssa_3 = phi block_0: ssa_0, block_7: ssa_1
90 * vec1 32 ssa_6 = load_const (0x00000004)
91 * vec1 32 ssa_7 = ilt ssa_5, ssa_6
92 * if ssa_7 {
93 * block block_5:
94 * } else {
95 * block block_6:
96 * break
97 * }
98 * block block_7:
99 * // Stuff from block 1
100 * // Stuff from block 2
101 * vec1 32 ssa_4 = load_const (0x00000001)
102 * vec1 32 ssa_5 = iadd ssa_2, ssa_4
103 * }
104 */
105 static bool
106 opt_peel_loop_initial_if(nir_loop *loop)
107 {
108 nir_block *header_block = nir_loop_first_block(loop);
109 MAYBE_UNUSED nir_block *prev_block =
110 nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node));
111
112 /* It would be insane if this were not true */
113 assert(_mesa_set_search(header_block->predecessors, prev_block));
114
115 /* The loop must have exactly one continue block which could be a block
116 * ending in a continue instruction or the "natural" continue from the
117 * last block in the loop back to the top.
118 */
119 if (header_block->predecessors->entries != 2)
120 return false;
121
122 nir_block *continue_block = find_continue_block(loop);
123
124 nir_cf_node *if_node = nir_cf_node_next(&header_block->cf_node);
125 if (!if_node || if_node->type != nir_cf_node_if)
126 return false;
127
128 nir_if *nif = nir_cf_node_as_if(if_node);
129 assert(nif->condition.is_ssa);
130
131 nir_ssa_def *cond = nif->condition.ssa;
132 if (cond->parent_instr->type != nir_instr_type_phi)
133 return false;
134
135 nir_phi_instr *cond_phi = nir_instr_as_phi(cond->parent_instr);
136 if (cond->parent_instr->block != header_block)
137 return false;
138
139 /* We already know we have exactly one continue */
140 assert(exec_list_length(&cond_phi->srcs) == 2);
141
142 uint32_t entry_val = 0, continue_val = 0;
143 nir_foreach_phi_src(src, cond_phi) {
144 assert(src->src.is_ssa);
145 nir_const_value *const_src = nir_src_as_const_value(src->src);
146 if (!const_src)
147 return false;
148
149 if (src->pred == continue_block) {
150 continue_val = const_src->u32[0];
151 } else {
152 assert(src->pred == prev_block);
153 entry_val = const_src->u32[0];
154 }
155 }
156
157 /* If they both execute or both don't execute, this is a job for
158 * nir_dead_cf, not this pass.
159 */
160 if ((entry_val && continue_val) || (!entry_val && !continue_val))
161 return false;
162
163 struct exec_list *continue_list, *entry_list;
164 if (continue_val) {
165 continue_list = &nif->then_list;
166 entry_list = &nif->else_list;
167 } else {
168 continue_list = &nif->else_list;
169 entry_list = &nif->then_list;
170 }
171
172 /* We want to be moving the contents of entry_list to above the loop so it
173 * can't contain any break or continue instructions.
174 */
175 foreach_list_typed(nir_cf_node, cf_node, node, entry_list) {
176 nir_foreach_block_in_cf_node(block, cf_node) {
177 nir_instr *last_instr = nir_block_last_instr(block);
178 if (last_instr && last_instr->type == nir_instr_type_jump)
179 return false;
180 }
181 }
182
183 /* We're about to re-arrange a bunch of blocks so make sure that we don't
184 * have deref uses which cross block boundaries. We don't want a deref
185 * accidentally ending up in a phi.
186 */
187 nir_rematerialize_derefs_in_use_blocks_impl(
188 nir_cf_node_get_function(&loop->cf_node));
189
190 /* Before we do anything, convert the loop to LCSSA. We're about to
191 * replace a bunch of SSA defs with registers and this will prevent any of
192 * it from leaking outside the loop.
193 */
194 nir_convert_loop_to_lcssa(loop);
195
196 nir_block *after_if_block =
197 nir_cf_node_as_block(nir_cf_node_next(&nif->cf_node));
198
199 /* Get rid of phis in the header block since we will be duplicating it */
200 nir_lower_phis_to_regs_block(header_block);
201 /* Get rid of phis after the if since dominance will change */
202 nir_lower_phis_to_regs_block(after_if_block);
203
204 /* Get rid of SSA defs in the pieces we're about to move around */
205 nir_lower_ssa_defs_to_regs_block(header_block);
206 nir_foreach_block_in_cf_node(block, &nif->cf_node)
207 nir_lower_ssa_defs_to_regs_block(block);
208
209 nir_cf_list header, tmp;
210 nir_cf_extract(&header, nir_before_block(header_block),
211 nir_after_block(header_block));
212
213 nir_cf_list_clone(&tmp, &header, &loop->cf_node, NULL);
214 nir_cf_reinsert(&tmp, nir_before_cf_node(&loop->cf_node));
215 nir_cf_extract(&tmp, nir_before_cf_list(entry_list),
216 nir_after_cf_list(entry_list));
217 nir_cf_reinsert(&tmp, nir_before_cf_node(&loop->cf_node));
218
219 nir_cf_reinsert(&header, nir_after_block_before_jump(continue_block));
220
221 /* Get continue block again as the previous reinsert might have removed the block. */
222 continue_block = find_continue_block(loop);
223
224 nir_cf_extract(&tmp, nir_before_cf_list(continue_list),
225 nir_after_cf_list(continue_list));
226 nir_cf_reinsert(&tmp, nir_after_block_before_jump(continue_block));
227
228 nir_cf_node_remove(&nif->cf_node);
229
230 return true;
231 }
232
233 static bool
234 is_block_empty(nir_block *block)
235 {
236 return nir_cf_node_is_last(&block->cf_node) &&
237 exec_list_is_empty(&block->instr_list);
238 }
239
240 static bool
241 nir_block_ends_in_continue(nir_block *block)
242 {
243 if (exec_list_is_empty(&block->instr_list))
244 return false;
245
246 nir_instr *instr = nir_block_last_instr(block);
247 return instr->type == nir_instr_type_jump &&
248 nir_instr_as_jump(instr)->type == nir_jump_continue;
249 }
250
251 /**
252 * This optimization turns:
253 *
254 * loop {
255 * ...
256 * if (cond) {
257 * do_work_1();
258 * continue;
259 * } else {
260 * }
261 * do_work_2();
262 * }
263 *
264 * into:
265 *
266 * loop {
267 * ...
268 * if (cond) {
269 * do_work_1();
270 * continue;
271 * } else {
272 * do_work_2();
273 * }
274 * }
275 *
276 * The continue should then be removed by nir_opt_trivial_continues() and the
277 * loop can potentially be unrolled.
278 *
279 * Note: do_work_2() is only ever blocks and nested loops. We could also nest
280 * other if-statments in the branch which would allow further continues to
281 * be removed. However in practice this can result in increased register
282 * pressure.
283 */
284 static bool
285 opt_if_loop_last_continue(nir_loop *loop)
286 {
287 /* Get the last if-stament in the loop */
288 nir_block *last_block = nir_loop_last_block(loop);
289 nir_cf_node *if_node = nir_cf_node_prev(&last_block->cf_node);
290 while (if_node) {
291 if (if_node->type == nir_cf_node_if)
292 break;
293
294 if_node = nir_cf_node_prev(if_node);
295 }
296
297 if (!if_node || if_node->type != nir_cf_node_if)
298 return false;
299
300 nir_if *nif = nir_cf_node_as_if(if_node);
301 nir_block *then_block = nir_if_last_then_block(nif);
302 nir_block *else_block = nir_if_last_else_block(nif);
303
304 bool then_ends_in_continue = nir_block_ends_in_continue(then_block);
305 bool else_ends_in_continue = nir_block_ends_in_continue(else_block);
306
307 /* If both branches end in a continue do nothing, this should be handled
308 * by nir_opt_dead_cf().
309 */
310 if (then_ends_in_continue && else_ends_in_continue)
311 return false;
312
313 if (!then_ends_in_continue && !else_ends_in_continue)
314 return false;
315
316 /* Move the last block of the loop inside the last if-statement */
317 nir_cf_list tmp;
318 nir_cf_extract(&tmp, nir_after_cf_node(if_node),
319 nir_after_block(last_block));
320 if (then_ends_in_continue) {
321 nir_cf_reinsert(&tmp, nir_after_cf_list(&nif->else_list));
322 } else {
323 nir_cf_reinsert(&tmp, nir_after_cf_list(&nif->then_list));
324 }
325
326 /* In order to avoid running nir_lower_regs_to_ssa_impl() every time an if
327 * opt makes progress we leave nir_opt_trivial_continues() to remove the
328 * continue now that the end of the loop has been simplified.
329 */
330
331 return true;
332 }
333
334 /**
335 * This optimization turns:
336 *
337 * if (cond) {
338 * } else {
339 * do_work();
340 * }
341 *
342 * into:
343 *
344 * if (!cond) {
345 * do_work();
346 * } else {
347 * }
348 */
349 static bool
350 opt_if_simplification(nir_builder *b, nir_if *nif)
351 {
352 /* Only simplify if the then block is empty and the else block is not. */
353 if (!is_block_empty(nir_if_first_then_block(nif)) ||
354 is_block_empty(nir_if_first_else_block(nif)))
355 return false;
356
357 /* Make sure the condition is a comparison operation. */
358 nir_instr *src_instr = nif->condition.ssa->parent_instr;
359 if (src_instr->type != nir_instr_type_alu)
360 return false;
361
362 nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr);
363 if (!nir_alu_instr_is_comparison(alu_instr))
364 return false;
365
366 /* Insert the inverted instruction and rewrite the condition. */
367 b->cursor = nir_after_instr(&alu_instr->instr);
368
369 nir_ssa_def *new_condition =
370 nir_inot(b, &alu_instr->dest.dest.ssa);
371
372 nir_if_rewrite_condition(nif, nir_src_for_ssa(new_condition));
373
374 /* Grab pointers to the last then/else blocks for fixing up the phis. */
375 nir_block *then_block = nir_if_last_then_block(nif);
376 nir_block *else_block = nir_if_last_else_block(nif);
377
378 /* Walk all the phis in the block immediately following the if statement and
379 * swap the blocks.
380 */
381 nir_block *after_if_block =
382 nir_cf_node_as_block(nir_cf_node_next(&nif->cf_node));
383
384 nir_foreach_instr(instr, after_if_block) {
385 if (instr->type != nir_instr_type_phi)
386 continue;
387
388 nir_phi_instr *phi = nir_instr_as_phi(instr);
389
390 foreach_list_typed(nir_phi_src, src, node, &phi->srcs) {
391 if (src->pred == else_block) {
392 src->pred = then_block;
393 } else if (src->pred == then_block) {
394 src->pred = else_block;
395 }
396 }
397 }
398
399 /* Finally, move the else block to the then block. */
400 nir_cf_list tmp;
401 nir_cf_extract(&tmp, nir_before_cf_list(&nif->else_list),
402 nir_after_cf_list(&nif->else_list));
403 nir_cf_reinsert(&tmp, nir_before_cf_list(&nif->then_list));
404
405 return true;
406 }
407
408 /**
409 * This optimization simplifies potential loop terminators which then allows
410 * other passes such as opt_if_simplification() and loop unrolling to progress
411 * further:
412 *
413 * if (cond) {
414 * ... then block instructions ...
415 * } else {
416 * ...
417 * break;
418 * }
419 *
420 * into:
421 *
422 * if (cond) {
423 * } else {
424 * ...
425 * break;
426 * }
427 * ... then block instructions ...
428 */
429 static bool
430 opt_if_loop_terminator(nir_if *nif)
431 {
432 nir_block *break_blk = NULL;
433 nir_block *continue_from_blk = NULL;
434 bool continue_from_then = true;
435
436 nir_block *last_then = nir_if_last_then_block(nif);
437 nir_block *last_else = nir_if_last_else_block(nif);
438
439 if (nir_block_ends_in_break(last_then)) {
440 break_blk = last_then;
441 continue_from_blk = last_else;
442 continue_from_then = false;
443 } else if (nir_block_ends_in_break(last_else)) {
444 break_blk = last_else;
445 continue_from_blk = last_then;
446 }
447
448 /* Continue if the if-statement contained no jumps at all */
449 if (!break_blk)
450 return false;
451
452 /* If the continue from block is empty then return as there is nothing to
453 * move.
454 */
455 nir_block *first_continue_from_blk = continue_from_then ?
456 nir_if_first_then_block(nif) :
457 nir_if_first_else_block(nif);
458 if (is_block_empty(first_continue_from_blk))
459 return false;
460
461 if (!nir_is_trivial_loop_if(nif, break_blk))
462 return false;
463
464 /* Finally, move the continue from branch after the if-statement. */
465 nir_cf_list tmp;
466 nir_cf_extract(&tmp, nir_before_block(first_continue_from_blk),
467 nir_after_block(continue_from_blk));
468 nir_cf_reinsert(&tmp, nir_after_cf_node(&nif->cf_node));
469
470 return true;
471 }
472
473 static bool
474 evaluate_if_condition(nir_if *nif, nir_cursor cursor, bool *value)
475 {
476 nir_block *use_block = nir_cursor_current_block(cursor);
477 if (nir_block_dominates(nir_if_first_then_block(nif), use_block)) {
478 *value = true;
479 return true;
480 } else if (nir_block_dominates(nir_if_first_else_block(nif), use_block)) {
481 *value = false;
482 return true;
483 } else {
484 return false;
485 }
486 }
487
488 static nir_ssa_def *
489 clone_alu_and_replace_src_defs(nir_builder *b, const nir_alu_instr *alu,
490 nir_ssa_def **src_defs)
491 {
492 nir_alu_instr *nalu = nir_alu_instr_create(b->shader, alu->op);
493 nalu->exact = alu->exact;
494
495 nir_ssa_dest_init(&nalu->instr, &nalu->dest.dest,
496 alu->dest.dest.ssa.num_components,
497 alu->dest.dest.ssa.bit_size, alu->dest.dest.ssa.name);
498
499 nalu->dest.saturate = alu->dest.saturate;
500 nalu->dest.write_mask = alu->dest.write_mask;
501
502 for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) {
503 assert(alu->src[i].src.is_ssa);
504 nalu->src[i].src = nir_src_for_ssa(src_defs[i]);
505 nalu->src[i].negate = alu->src[i].negate;
506 nalu->src[i].abs = alu->src[i].abs;
507 memcpy(nalu->src[i].swizzle, alu->src[i].swizzle,
508 sizeof(nalu->src[i].swizzle));
509 }
510
511 nir_builder_instr_insert(b, &nalu->instr);
512
513 return &nalu->dest.dest.ssa;;
514 }
515
516 /*
517 * This propagates if condition evaluation down the chain of some alu
518 * instructions. For example by checking the use of some of the following alu
519 * instruction we can eventually replace ssa_107 with NIR_TRUE.
520 *
521 * loop {
522 * block block_1:
523 * vec1 32 ssa_85 = load_const (0x00000002)
524 * vec1 32 ssa_86 = ieq ssa_48, ssa_85
525 * vec1 32 ssa_87 = load_const (0x00000001)
526 * vec1 32 ssa_88 = ieq ssa_48, ssa_87
527 * vec1 32 ssa_89 = ior ssa_86, ssa_88
528 * vec1 32 ssa_90 = ieq ssa_48, ssa_0
529 * vec1 32 ssa_91 = ior ssa_89, ssa_90
530 * if ssa_86 {
531 * block block_2:
532 * ...
533 * break
534 * } else {
535 * block block_3:
536 * }
537 * block block_4:
538 * if ssa_88 {
539 * block block_5:
540 * ...
541 * break
542 * } else {
543 * block block_6:
544 * }
545 * block block_7:
546 * if ssa_90 {
547 * block block_8:
548 * ...
549 * break
550 * } else {
551 * block block_9:
552 * }
553 * block block_10:
554 * vec1 32 ssa_107 = inot ssa_91
555 * if ssa_107 {
556 * block block_11:
557 * break
558 * } else {
559 * block block_12:
560 * }
561 * }
562 */
563 static bool
564 propagate_condition_eval(nir_builder *b, nir_if *nif, nir_src *use_src,
565 nir_src *alu_use, nir_alu_instr *alu,
566 bool is_if_condition)
567 {
568 bool bool_value;
569 b->cursor = nir_before_src(alu_use, is_if_condition);
570 if (!evaluate_if_condition(nif, b->cursor, &bool_value))
571 return false;
572
573 nir_ssa_def *def[4] = {0};
574 for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) {
575 if (alu->src[i].src.ssa == use_src->ssa) {
576 def[i] = nir_imm_bool(b, bool_value);
577 } else {
578 def[i] = alu->src[i].src.ssa;
579 }
580 }
581
582 nir_ssa_def *nalu = clone_alu_and_replace_src_defs(b, alu, def);
583
584 /* Rewrite use to use new alu instruction */
585 nir_src new_src = nir_src_for_ssa(nalu);
586
587 if (is_if_condition)
588 nir_if_rewrite_condition(alu_use->parent_if, new_src);
589 else
590 nir_instr_rewrite_src(alu_use->parent_instr, alu_use, new_src);
591
592 return true;
593 }
594
595 static bool
596 can_propagate_through_alu(nir_src *src)
597 {
598 if (src->parent_instr->type != nir_instr_type_alu)
599 return false;
600
601 nir_alu_instr *alu = nir_instr_as_alu(src->parent_instr);
602 switch (alu->op) {
603 case nir_op_ior:
604 case nir_op_iand:
605 case nir_op_inot:
606 case nir_op_b2i32:
607 return true;
608 case nir_op_bcsel:
609 return src == &alu->src[0].src;
610 default:
611 return false;
612 }
613 }
614
615 static bool
616 evaluate_condition_use(nir_builder *b, nir_if *nif, nir_src *use_src,
617 bool is_if_condition)
618 {
619 bool progress = false;
620
621 b->cursor = nir_before_src(use_src, is_if_condition);
622
623 bool bool_value;
624 if (evaluate_if_condition(nif, b->cursor, &bool_value)) {
625 /* Rewrite use to use const */
626 nir_src imm_src = nir_src_for_ssa(nir_imm_bool(b, bool_value));
627 if (is_if_condition)
628 nir_if_rewrite_condition(use_src->parent_if, imm_src);
629 else
630 nir_instr_rewrite_src(use_src->parent_instr, use_src, imm_src);
631
632 progress = true;
633 }
634
635 if (!is_if_condition && can_propagate_through_alu(use_src)) {
636 nir_alu_instr *alu = nir_instr_as_alu(use_src->parent_instr);
637
638 nir_foreach_use_safe(alu_use, &alu->dest.dest.ssa) {
639 progress |= propagate_condition_eval(b, nif, use_src, alu_use, alu,
640 false);
641 }
642
643 nir_foreach_if_use_safe(alu_use, &alu->dest.dest.ssa) {
644 progress |= propagate_condition_eval(b, nif, use_src, alu_use, alu,
645 true);
646 }
647 }
648
649 return progress;
650 }
651
652 static bool
653 opt_if_evaluate_condition_use(nir_builder *b, nir_if *nif)
654 {
655 bool progress = false;
656
657 /* Evaluate any uses of the if condition inside the if branches */
658 assert(nif->condition.is_ssa);
659 nir_foreach_use_safe(use_src, nif->condition.ssa) {
660 progress |= evaluate_condition_use(b, nif, use_src, false);
661 }
662
663 nir_foreach_if_use_safe(use_src, nif->condition.ssa) {
664 if (use_src->parent_if != nif)
665 progress |= evaluate_condition_use(b, nif, use_src, true);
666 }
667
668 return progress;
669 }
670
671 static bool
672 opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)
673 {
674 bool progress = false;
675 foreach_list_typed(nir_cf_node, cf_node, node, cf_list) {
676 switch (cf_node->type) {
677 case nir_cf_node_block:
678 break;
679
680 case nir_cf_node_if: {
681 nir_if *nif = nir_cf_node_as_if(cf_node);
682 progress |= opt_if_cf_list(b, &nif->then_list);
683 progress |= opt_if_cf_list(b, &nif->else_list);
684 progress |= opt_if_loop_terminator(nif);
685 progress |= opt_if_simplification(b, nif);
686 break;
687 }
688
689 case nir_cf_node_loop: {
690 nir_loop *loop = nir_cf_node_as_loop(cf_node);
691 progress |= opt_if_cf_list(b, &loop->body);
692 progress |= opt_peel_loop_initial_if(loop);
693 progress |= opt_if_loop_last_continue(loop);
694 break;
695 }
696
697 case nir_cf_node_function:
698 unreachable("Invalid cf type");
699 }
700 }
701
702 return progress;
703 }
704
705 /**
706 * These optimisations depend on nir_metadata_block_index and therefore must
707 * not do anything to cause the metadata to become invalid.
708 */
709 static bool
710 opt_if_safe_cf_list(nir_builder *b, struct exec_list *cf_list)
711 {
712 bool progress = false;
713 foreach_list_typed(nir_cf_node, cf_node, node, cf_list) {
714 switch (cf_node->type) {
715 case nir_cf_node_block:
716 break;
717
718 case nir_cf_node_if: {
719 nir_if *nif = nir_cf_node_as_if(cf_node);
720 progress |= opt_if_safe_cf_list(b, &nif->then_list);
721 progress |= opt_if_safe_cf_list(b, &nif->else_list);
722 progress |= opt_if_evaluate_condition_use(b, nif);
723 break;
724 }
725
726 case nir_cf_node_loop: {
727 nir_loop *loop = nir_cf_node_as_loop(cf_node);
728 progress |= opt_if_safe_cf_list(b, &loop->body);
729 break;
730 }
731
732 case nir_cf_node_function:
733 unreachable("Invalid cf type");
734 }
735 }
736
737 return progress;
738 }
739
740 bool
741 nir_opt_if(nir_shader *shader)
742 {
743 bool progress = false;
744
745 nir_foreach_function(function, shader) {
746 if (function->impl == NULL)
747 continue;
748
749 nir_builder b;
750 nir_builder_init(&b, function->impl);
751
752 nir_metadata_require(function->impl, nir_metadata_block_index |
753 nir_metadata_dominance);
754 progress = opt_if_safe_cf_list(&b, &function->impl->body);
755 nir_metadata_preserve(function->impl, nir_metadata_block_index |
756 nir_metadata_dominance);
757
758 if (opt_if_cf_list(&b, &function->impl->body)) {
759 nir_metadata_preserve(function->impl, nir_metadata_none);
760
761 /* If that made progress, we're no longer really in SSA form. We
762 * need to convert registers back into SSA defs and clean up SSA defs
763 * that don't dominate their uses.
764 */
765 nir_lower_regs_to_ssa_impl(function->impl);
766
767 progress = true;
768 }
769 }
770
771 return progress;
772 }