nir: Refactor code that checks phi nodes in opt_peel_loop_initial_if
[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 * Does a phi have one constant value from outside a loop and one from inside?
53 */
54 static bool
55 phi_has_constant_from_outside_and_one_from_inside_loop(nir_phi_instr *phi,
56 const nir_block *continue_block,
57 uint32_t *entry_val,
58 uint32_t *continue_val)
59 {
60 /* We already know we have exactly one continue */
61 assert(exec_list_length(&phi->srcs) == 2);
62
63 *entry_val = 0;
64 *continue_val = 0;
65
66 nir_foreach_phi_src(src, phi) {
67 assert(src->src.is_ssa);
68 nir_const_value *const_src = nir_src_as_const_value(src->src);
69 if (!const_src)
70 return false;
71
72 if (src->pred == continue_block) {
73 *continue_val = const_src->u32[0];
74 } else {
75 *entry_val = const_src->u32[0];
76 }
77 }
78
79 return true;
80 }
81
82 /**
83 * This optimization detects if statements at the tops of loops where the
84 * condition is a phi node of two constants and moves half of the if to above
85 * the loop and the other half of the if to the end of the loop. A simple for
86 * loop "for (int i = 0; i < 4; i++)", when run through the SPIR-V front-end,
87 * ends up looking something like this:
88 *
89 * vec1 32 ssa_0 = load_const (0x00000000)
90 * vec1 32 ssa_1 = load_const (0xffffffff)
91 * loop {
92 * block block_1:
93 * vec1 32 ssa_2 = phi block_0: ssa_0, block_7: ssa_5
94 * vec1 32 ssa_3 = phi block_0: ssa_0, block_7: ssa_1
95 * if ssa_2 {
96 * block block_2:
97 * vec1 32 ssa_4 = load_const (0x00000001)
98 * vec1 32 ssa_5 = iadd ssa_2, ssa_4
99 * } else {
100 * block block_3:
101 * }
102 * block block_4:
103 * vec1 32 ssa_6 = load_const (0x00000004)
104 * vec1 32 ssa_7 = ilt ssa_5, ssa_6
105 * if ssa_7 {
106 * block block_5:
107 * } else {
108 * block block_6:
109 * break
110 * }
111 * block block_7:
112 * }
113 *
114 * This turns it into something like this:
115 *
116 * // Stuff from block 1
117 * // Stuff from block 3
118 * loop {
119 * block block_1:
120 * vec1 32 ssa_3 = phi block_0: ssa_0, block_7: ssa_1
121 * vec1 32 ssa_6 = load_const (0x00000004)
122 * vec1 32 ssa_7 = ilt ssa_5, ssa_6
123 * if ssa_7 {
124 * block block_5:
125 * } else {
126 * block block_6:
127 * break
128 * }
129 * block block_7:
130 * // Stuff from block 1
131 * // Stuff from block 2
132 * vec1 32 ssa_4 = load_const (0x00000001)
133 * vec1 32 ssa_5 = iadd ssa_2, ssa_4
134 * }
135 */
136 static bool
137 opt_peel_loop_initial_if(nir_loop *loop)
138 {
139 nir_block *header_block = nir_loop_first_block(loop);
140 MAYBE_UNUSED nir_block *prev_block =
141 nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node));
142
143 /* It would be insane if this were not true */
144 assert(_mesa_set_search(header_block->predecessors, prev_block));
145
146 /* The loop must have exactly one continue block which could be a block
147 * ending in a continue instruction or the "natural" continue from the
148 * last block in the loop back to the top.
149 */
150 if (header_block->predecessors->entries != 2)
151 return false;
152
153 nir_block *continue_block = find_continue_block(loop);
154
155 nir_cf_node *if_node = nir_cf_node_next(&header_block->cf_node);
156 if (!if_node || if_node->type != nir_cf_node_if)
157 return false;
158
159 nir_if *nif = nir_cf_node_as_if(if_node);
160 assert(nif->condition.is_ssa);
161
162 nir_ssa_def *cond = nif->condition.ssa;
163 if (cond->parent_instr->type != nir_instr_type_phi)
164 return false;
165
166 nir_phi_instr *cond_phi = nir_instr_as_phi(cond->parent_instr);
167 if (cond->parent_instr->block != header_block)
168 return false;
169
170 uint32_t entry_val = 0, continue_val = 0;
171 if (!phi_has_constant_from_outside_and_one_from_inside_loop(cond_phi,
172 continue_block,
173 &entry_val,
174 &continue_val))
175 return false;
176
177 /* If they both execute or both don't execute, this is a job for
178 * nir_dead_cf, not this pass.
179 */
180 if ((entry_val && continue_val) || (!entry_val && !continue_val))
181 return false;
182
183 struct exec_list *continue_list, *entry_list;
184 if (continue_val) {
185 continue_list = &nif->then_list;
186 entry_list = &nif->else_list;
187 } else {
188 continue_list = &nif->else_list;
189 entry_list = &nif->then_list;
190 }
191
192 /* We want to be moving the contents of entry_list to above the loop so it
193 * can't contain any break or continue instructions.
194 */
195 foreach_list_typed(nir_cf_node, cf_node, node, entry_list) {
196 nir_foreach_block_in_cf_node(block, cf_node) {
197 nir_instr *last_instr = nir_block_last_instr(block);
198 if (last_instr && last_instr->type == nir_instr_type_jump)
199 return false;
200 }
201 }
202
203 /* We're about to re-arrange a bunch of blocks so make sure that we don't
204 * have deref uses which cross block boundaries. We don't want a deref
205 * accidentally ending up in a phi.
206 */
207 nir_rematerialize_derefs_in_use_blocks_impl(
208 nir_cf_node_get_function(&loop->cf_node));
209
210 /* Before we do anything, convert the loop to LCSSA. We're about to
211 * replace a bunch of SSA defs with registers and this will prevent any of
212 * it from leaking outside the loop.
213 */
214 nir_convert_loop_to_lcssa(loop);
215
216 nir_block *after_if_block =
217 nir_cf_node_as_block(nir_cf_node_next(&nif->cf_node));
218
219 /* Get rid of phis in the header block since we will be duplicating it */
220 nir_lower_phis_to_regs_block(header_block);
221 /* Get rid of phis after the if since dominance will change */
222 nir_lower_phis_to_regs_block(after_if_block);
223
224 /* Get rid of SSA defs in the pieces we're about to move around */
225 nir_lower_ssa_defs_to_regs_block(header_block);
226 nir_foreach_block_in_cf_node(block, &nif->cf_node)
227 nir_lower_ssa_defs_to_regs_block(block);
228
229 nir_cf_list header, tmp;
230 nir_cf_extract(&header, nir_before_block(header_block),
231 nir_after_block(header_block));
232
233 nir_cf_list_clone(&tmp, &header, &loop->cf_node, NULL);
234 nir_cf_reinsert(&tmp, nir_before_cf_node(&loop->cf_node));
235 nir_cf_extract(&tmp, nir_before_cf_list(entry_list),
236 nir_after_cf_list(entry_list));
237 nir_cf_reinsert(&tmp, nir_before_cf_node(&loop->cf_node));
238
239 nir_cf_reinsert(&header, nir_after_block_before_jump(continue_block));
240
241 /* Get continue block again as the previous reinsert might have removed the block. */
242 continue_block = find_continue_block(loop);
243
244 nir_cf_extract(&tmp, nir_before_cf_list(continue_list),
245 nir_after_cf_list(continue_list));
246 nir_cf_reinsert(&tmp, nir_after_block_before_jump(continue_block));
247
248 nir_cf_node_remove(&nif->cf_node);
249
250 return true;
251 }
252
253 static bool
254 is_block_empty(nir_block *block)
255 {
256 return nir_cf_node_is_last(&block->cf_node) &&
257 exec_list_is_empty(&block->instr_list);
258 }
259
260 static bool
261 nir_block_ends_in_continue(nir_block *block)
262 {
263 if (exec_list_is_empty(&block->instr_list))
264 return false;
265
266 nir_instr *instr = nir_block_last_instr(block);
267 return instr->type == nir_instr_type_jump &&
268 nir_instr_as_jump(instr)->type == nir_jump_continue;
269 }
270
271 /**
272 * This optimization turns:
273 *
274 * loop {
275 * ...
276 * if (cond) {
277 * do_work_1();
278 * continue;
279 * } else {
280 * }
281 * do_work_2();
282 * }
283 *
284 * into:
285 *
286 * loop {
287 * ...
288 * if (cond) {
289 * do_work_1();
290 * continue;
291 * } else {
292 * do_work_2();
293 * }
294 * }
295 *
296 * The continue should then be removed by nir_opt_trivial_continues() and the
297 * loop can potentially be unrolled.
298 *
299 * Note: do_work_2() is only ever blocks and nested loops. We could also nest
300 * other if-statments in the branch which would allow further continues to
301 * be removed. However in practice this can result in increased register
302 * pressure.
303 */
304 static bool
305 opt_if_loop_last_continue(nir_loop *loop)
306 {
307 /* Get the last if-stament in the loop */
308 nir_block *last_block = nir_loop_last_block(loop);
309 nir_cf_node *if_node = nir_cf_node_prev(&last_block->cf_node);
310 while (if_node) {
311 if (if_node->type == nir_cf_node_if)
312 break;
313
314 if_node = nir_cf_node_prev(if_node);
315 }
316
317 if (!if_node || if_node->type != nir_cf_node_if)
318 return false;
319
320 nir_if *nif = nir_cf_node_as_if(if_node);
321 nir_block *then_block = nir_if_last_then_block(nif);
322 nir_block *else_block = nir_if_last_else_block(nif);
323
324 bool then_ends_in_continue = nir_block_ends_in_continue(then_block);
325 bool else_ends_in_continue = nir_block_ends_in_continue(else_block);
326
327 /* If both branches end in a continue do nothing, this should be handled
328 * by nir_opt_dead_cf().
329 */
330 if (then_ends_in_continue && else_ends_in_continue)
331 return false;
332
333 if (!then_ends_in_continue && !else_ends_in_continue)
334 return false;
335
336 /* Move the last block of the loop inside the last if-statement */
337 nir_cf_list tmp;
338 nir_cf_extract(&tmp, nir_after_cf_node(if_node),
339 nir_after_block(last_block));
340 if (then_ends_in_continue) {
341 nir_cursor last_blk_cursor = nir_after_cf_list(&nif->else_list);
342 nir_cf_reinsert(&tmp,
343 nir_after_block_before_jump(last_blk_cursor.block));
344 } else {
345 nir_cursor last_blk_cursor = nir_after_cf_list(&nif->then_list);
346 nir_cf_reinsert(&tmp,
347 nir_after_block_before_jump(last_blk_cursor.block));
348 }
349
350 /* In order to avoid running nir_lower_regs_to_ssa_impl() every time an if
351 * opt makes progress we leave nir_opt_trivial_continues() to remove the
352 * continue now that the end of the loop has been simplified.
353 */
354
355 return true;
356 }
357
358 /* Walk all the phis in the block immediately following the if statement and
359 * swap the blocks.
360 */
361 static void
362 rewrite_phi_predecessor_blocks(nir_if *nif,
363 nir_block *old_then_block,
364 nir_block *old_else_block,
365 nir_block *new_then_block,
366 nir_block *new_else_block)
367 {
368 nir_block *after_if_block =
369 nir_cf_node_as_block(nir_cf_node_next(&nif->cf_node));
370
371 nir_foreach_instr(instr, after_if_block) {
372 if (instr->type != nir_instr_type_phi)
373 continue;
374
375 nir_phi_instr *phi = nir_instr_as_phi(instr);
376
377 foreach_list_typed(nir_phi_src, src, node, &phi->srcs) {
378 if (src->pred == old_then_block) {
379 src->pred = new_then_block;
380 } else if (src->pred == old_else_block) {
381 src->pred = new_else_block;
382 }
383 }
384 }
385 }
386
387 /**
388 * This optimization turns:
389 *
390 * if (cond) {
391 * } else {
392 * do_work();
393 * }
394 *
395 * into:
396 *
397 * if (!cond) {
398 * do_work();
399 * } else {
400 * }
401 */
402 static bool
403 opt_if_simplification(nir_builder *b, nir_if *nif)
404 {
405 /* Only simplify if the then block is empty and the else block is not. */
406 if (!is_block_empty(nir_if_first_then_block(nif)) ||
407 is_block_empty(nir_if_first_else_block(nif)))
408 return false;
409
410 /* Make sure the condition is a comparison operation. */
411 nir_instr *src_instr = nif->condition.ssa->parent_instr;
412 if (src_instr->type != nir_instr_type_alu)
413 return false;
414
415 nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr);
416 if (!nir_alu_instr_is_comparison(alu_instr))
417 return false;
418
419 /* Insert the inverted instruction and rewrite the condition. */
420 b->cursor = nir_after_instr(&alu_instr->instr);
421
422 nir_ssa_def *new_condition =
423 nir_inot(b, &alu_instr->dest.dest.ssa);
424
425 nir_if_rewrite_condition(nif, nir_src_for_ssa(new_condition));
426
427 /* Grab pointers to the last then/else blocks for fixing up the phis. */
428 nir_block *then_block = nir_if_last_then_block(nif);
429 nir_block *else_block = nir_if_last_else_block(nif);
430
431 rewrite_phi_predecessor_blocks(nif, then_block, else_block, else_block,
432 then_block);
433
434 /* Finally, move the else block to the then block. */
435 nir_cf_list tmp;
436 nir_cf_extract(&tmp, nir_before_cf_list(&nif->else_list),
437 nir_after_cf_list(&nif->else_list));
438 nir_cf_reinsert(&tmp, nir_before_cf_list(&nif->then_list));
439
440 return true;
441 }
442
443 /**
444 * This optimization simplifies potential loop terminators which then allows
445 * other passes such as opt_if_simplification() and loop unrolling to progress
446 * further:
447 *
448 * if (cond) {
449 * ... then block instructions ...
450 * } else {
451 * ...
452 * break;
453 * }
454 *
455 * into:
456 *
457 * if (cond) {
458 * } else {
459 * ...
460 * break;
461 * }
462 * ... then block instructions ...
463 */
464 static bool
465 opt_if_loop_terminator(nir_if *nif)
466 {
467 nir_block *break_blk = NULL;
468 nir_block *continue_from_blk = NULL;
469 bool continue_from_then = true;
470
471 nir_block *last_then = nir_if_last_then_block(nif);
472 nir_block *last_else = nir_if_last_else_block(nif);
473
474 if (nir_block_ends_in_break(last_then)) {
475 break_blk = last_then;
476 continue_from_blk = last_else;
477 continue_from_then = false;
478 } else if (nir_block_ends_in_break(last_else)) {
479 break_blk = last_else;
480 continue_from_blk = last_then;
481 }
482
483 /* Continue if the if-statement contained no jumps at all */
484 if (!break_blk)
485 return false;
486
487 /* If the continue from block is empty then return as there is nothing to
488 * move.
489 */
490 nir_block *first_continue_from_blk = continue_from_then ?
491 nir_if_first_then_block(nif) :
492 nir_if_first_else_block(nif);
493 if (is_block_empty(first_continue_from_blk))
494 return false;
495
496 if (!nir_is_trivial_loop_if(nif, break_blk))
497 return false;
498
499 /* Finally, move the continue from branch after the if-statement. */
500 nir_cf_list tmp;
501 nir_cf_extract(&tmp, nir_before_block(first_continue_from_blk),
502 nir_after_block(continue_from_blk));
503 nir_cf_reinsert(&tmp, nir_after_cf_node(&nif->cf_node));
504
505 return true;
506 }
507
508 static bool
509 evaluate_if_condition(nir_if *nif, nir_cursor cursor, bool *value)
510 {
511 nir_block *use_block = nir_cursor_current_block(cursor);
512 if (nir_block_dominates(nir_if_first_then_block(nif), use_block)) {
513 *value = true;
514 return true;
515 } else if (nir_block_dominates(nir_if_first_else_block(nif), use_block)) {
516 *value = false;
517 return true;
518 } else {
519 return false;
520 }
521 }
522
523 static nir_ssa_def *
524 clone_alu_and_replace_src_defs(nir_builder *b, const nir_alu_instr *alu,
525 nir_ssa_def **src_defs)
526 {
527 nir_alu_instr *nalu = nir_alu_instr_create(b->shader, alu->op);
528 nalu->exact = alu->exact;
529
530 nir_ssa_dest_init(&nalu->instr, &nalu->dest.dest,
531 alu->dest.dest.ssa.num_components,
532 alu->dest.dest.ssa.bit_size, alu->dest.dest.ssa.name);
533
534 nalu->dest.saturate = alu->dest.saturate;
535 nalu->dest.write_mask = alu->dest.write_mask;
536
537 for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) {
538 assert(alu->src[i].src.is_ssa);
539 nalu->src[i].src = nir_src_for_ssa(src_defs[i]);
540 nalu->src[i].negate = alu->src[i].negate;
541 nalu->src[i].abs = alu->src[i].abs;
542 memcpy(nalu->src[i].swizzle, alu->src[i].swizzle,
543 sizeof(nalu->src[i].swizzle));
544 }
545
546 nir_builder_instr_insert(b, &nalu->instr);
547
548 return &nalu->dest.dest.ssa;;
549 }
550
551 /*
552 * This propagates if condition evaluation down the chain of some alu
553 * instructions. For example by checking the use of some of the following alu
554 * instruction we can eventually replace ssa_107 with NIR_TRUE.
555 *
556 * loop {
557 * block block_1:
558 * vec1 32 ssa_85 = load_const (0x00000002)
559 * vec1 32 ssa_86 = ieq ssa_48, ssa_85
560 * vec1 32 ssa_87 = load_const (0x00000001)
561 * vec1 32 ssa_88 = ieq ssa_48, ssa_87
562 * vec1 32 ssa_89 = ior ssa_86, ssa_88
563 * vec1 32 ssa_90 = ieq ssa_48, ssa_0
564 * vec1 32 ssa_91 = ior ssa_89, ssa_90
565 * if ssa_86 {
566 * block block_2:
567 * ...
568 * break
569 * } else {
570 * block block_3:
571 * }
572 * block block_4:
573 * if ssa_88 {
574 * block block_5:
575 * ...
576 * break
577 * } else {
578 * block block_6:
579 * }
580 * block block_7:
581 * if ssa_90 {
582 * block block_8:
583 * ...
584 * break
585 * } else {
586 * block block_9:
587 * }
588 * block block_10:
589 * vec1 32 ssa_107 = inot ssa_91
590 * if ssa_107 {
591 * block block_11:
592 * break
593 * } else {
594 * block block_12:
595 * }
596 * }
597 */
598 static bool
599 propagate_condition_eval(nir_builder *b, nir_if *nif, nir_src *use_src,
600 nir_src *alu_use, nir_alu_instr *alu,
601 bool is_if_condition)
602 {
603 bool bool_value;
604 b->cursor = nir_before_src(alu_use, is_if_condition);
605 if (!evaluate_if_condition(nif, b->cursor, &bool_value))
606 return false;
607
608 nir_ssa_def *def[4] = {0};
609 for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) {
610 if (alu->src[i].src.ssa == use_src->ssa) {
611 def[i] = nir_imm_bool(b, bool_value);
612 } else {
613 def[i] = alu->src[i].src.ssa;
614 }
615 }
616
617 nir_ssa_def *nalu = clone_alu_and_replace_src_defs(b, alu, def);
618
619 /* Rewrite use to use new alu instruction */
620 nir_src new_src = nir_src_for_ssa(nalu);
621
622 if (is_if_condition)
623 nir_if_rewrite_condition(alu_use->parent_if, new_src);
624 else
625 nir_instr_rewrite_src(alu_use->parent_instr, alu_use, new_src);
626
627 return true;
628 }
629
630 static bool
631 can_propagate_through_alu(nir_src *src)
632 {
633 if (src->parent_instr->type != nir_instr_type_alu)
634 return false;
635
636 nir_alu_instr *alu = nir_instr_as_alu(src->parent_instr);
637 switch (alu->op) {
638 case nir_op_ior:
639 case nir_op_iand:
640 case nir_op_inot:
641 case nir_op_b2i32:
642 return true;
643 case nir_op_bcsel:
644 return src == &alu->src[0].src;
645 default:
646 return false;
647 }
648 }
649
650 static bool
651 evaluate_condition_use(nir_builder *b, nir_if *nif, nir_src *use_src,
652 bool is_if_condition)
653 {
654 bool progress = false;
655
656 b->cursor = nir_before_src(use_src, is_if_condition);
657
658 bool bool_value;
659 if (evaluate_if_condition(nif, b->cursor, &bool_value)) {
660 /* Rewrite use to use const */
661 nir_src imm_src = nir_src_for_ssa(nir_imm_bool(b, bool_value));
662 if (is_if_condition)
663 nir_if_rewrite_condition(use_src->parent_if, imm_src);
664 else
665 nir_instr_rewrite_src(use_src->parent_instr, use_src, imm_src);
666
667 progress = true;
668 }
669
670 if (!is_if_condition && can_propagate_through_alu(use_src)) {
671 nir_alu_instr *alu = nir_instr_as_alu(use_src->parent_instr);
672
673 nir_foreach_use_safe(alu_use, &alu->dest.dest.ssa) {
674 progress |= propagate_condition_eval(b, nif, use_src, alu_use, alu,
675 false);
676 }
677
678 nir_foreach_if_use_safe(alu_use, &alu->dest.dest.ssa) {
679 progress |= propagate_condition_eval(b, nif, use_src, alu_use, alu,
680 true);
681 }
682 }
683
684 return progress;
685 }
686
687 static bool
688 opt_if_evaluate_condition_use(nir_builder *b, nir_if *nif)
689 {
690 bool progress = false;
691
692 /* Evaluate any uses of the if condition inside the if branches */
693 assert(nif->condition.is_ssa);
694 nir_foreach_use_safe(use_src, nif->condition.ssa) {
695 progress |= evaluate_condition_use(b, nif, use_src, false);
696 }
697
698 nir_foreach_if_use_safe(use_src, nif->condition.ssa) {
699 if (use_src->parent_if != nif)
700 progress |= evaluate_condition_use(b, nif, use_src, true);
701 }
702
703 return progress;
704 }
705
706 static void
707 simple_merge_if(nir_if *dest_if, nir_if *src_if, bool dest_if_then,
708 bool src_if_then)
709 {
710 /* Now merge the if branch */
711 nir_block *dest_blk = dest_if_then ? nir_if_last_then_block(dest_if)
712 : nir_if_last_else_block(dest_if);
713
714 struct exec_list *list = src_if_then ? &src_if->then_list
715 : &src_if->else_list;
716
717 nir_cf_list if_cf_list;
718 nir_cf_extract(&if_cf_list, nir_before_cf_list(list),
719 nir_after_cf_list(list));
720 nir_cf_reinsert(&if_cf_list, nir_after_block(dest_blk));
721 }
722
723 static bool
724 opt_if_merge(nir_if *nif)
725 {
726 bool progress = false;
727
728 nir_block *next_blk = nir_cf_node_cf_tree_next(&nif->cf_node);
729 if (next_blk && nif->condition.is_ssa) {
730 nir_if *next_if = nir_block_get_following_if(next_blk);
731 if (next_if && next_if->condition.is_ssa) {
732
733 /* Here we merge two consecutive ifs that have the same
734 * condition e.g:
735 *
736 * if ssa_12 {
737 * ...
738 * } else {
739 * ...
740 * }
741 * if ssa_12 {
742 * ...
743 * } else {
744 * ...
745 * }
746 *
747 * Note: This only merges if-statements when the block between them
748 * is empty. The reason we don't try to merge ifs that just have phis
749 * between them is because this can results in increased register
750 * pressure. For example when merging if ladders created by indirect
751 * indexing.
752 */
753 if (nif->condition.ssa == next_if->condition.ssa &&
754 exec_list_is_empty(&next_blk->instr_list)) {
755
756 simple_merge_if(nif, next_if, true, true);
757 simple_merge_if(nif, next_if, false, false);
758
759 nir_block *new_then_block = nir_if_last_then_block(nif);
760 nir_block *new_else_block = nir_if_last_else_block(nif);
761
762 nir_block *old_then_block = nir_if_last_then_block(next_if);
763 nir_block *old_else_block = nir_if_last_else_block(next_if);
764
765 /* Rewrite the predecessor block for any phis following the second
766 * if-statement.
767 */
768 rewrite_phi_predecessor_blocks(next_if, old_then_block,
769 old_else_block,
770 new_then_block,
771 new_else_block);
772
773 /* Move phis after merged if to avoid them being deleted when we
774 * remove the merged if-statement.
775 */
776 nir_block *after_next_if_block =
777 nir_cf_node_as_block(nir_cf_node_next(&next_if->cf_node));
778
779 nir_foreach_instr_safe(instr, after_next_if_block) {
780 if (instr->type != nir_instr_type_phi)
781 break;
782
783 exec_node_remove(&instr->node);
784 exec_list_push_tail(&next_blk->instr_list, &instr->node);
785 instr->block = next_blk;
786 }
787
788 nir_cf_node_remove(&next_if->cf_node);
789
790 progress = true;
791 }
792 }
793 }
794
795 return progress;
796 }
797
798 static bool
799 opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)
800 {
801 bool progress = false;
802 foreach_list_typed(nir_cf_node, cf_node, node, cf_list) {
803 switch (cf_node->type) {
804 case nir_cf_node_block:
805 break;
806
807 case nir_cf_node_if: {
808 nir_if *nif = nir_cf_node_as_if(cf_node);
809 progress |= opt_if_cf_list(b, &nif->then_list);
810 progress |= opt_if_cf_list(b, &nif->else_list);
811 progress |= opt_if_loop_terminator(nif);
812 progress |= opt_if_merge(nif);
813 progress |= opt_if_simplification(b, nif);
814 break;
815 }
816
817 case nir_cf_node_loop: {
818 nir_loop *loop = nir_cf_node_as_loop(cf_node);
819 progress |= opt_if_cf_list(b, &loop->body);
820 progress |= opt_peel_loop_initial_if(loop);
821 progress |= opt_if_loop_last_continue(loop);
822 break;
823 }
824
825 case nir_cf_node_function:
826 unreachable("Invalid cf type");
827 }
828 }
829
830 return progress;
831 }
832
833 /**
834 * These optimisations depend on nir_metadata_block_index and therefore must
835 * not do anything to cause the metadata to become invalid.
836 */
837 static bool
838 opt_if_safe_cf_list(nir_builder *b, struct exec_list *cf_list)
839 {
840 bool progress = false;
841 foreach_list_typed(nir_cf_node, cf_node, node, cf_list) {
842 switch (cf_node->type) {
843 case nir_cf_node_block:
844 break;
845
846 case nir_cf_node_if: {
847 nir_if *nif = nir_cf_node_as_if(cf_node);
848 progress |= opt_if_safe_cf_list(b, &nif->then_list);
849 progress |= opt_if_safe_cf_list(b, &nif->else_list);
850 progress |= opt_if_evaluate_condition_use(b, nif);
851 break;
852 }
853
854 case nir_cf_node_loop: {
855 nir_loop *loop = nir_cf_node_as_loop(cf_node);
856 progress |= opt_if_safe_cf_list(b, &loop->body);
857 break;
858 }
859
860 case nir_cf_node_function:
861 unreachable("Invalid cf type");
862 }
863 }
864
865 return progress;
866 }
867
868 bool
869 nir_opt_if(nir_shader *shader)
870 {
871 bool progress = false;
872
873 nir_foreach_function(function, shader) {
874 if (function->impl == NULL)
875 continue;
876
877 nir_builder b;
878 nir_builder_init(&b, function->impl);
879
880 nir_metadata_require(function->impl, nir_metadata_block_index |
881 nir_metadata_dominance);
882 progress = opt_if_safe_cf_list(&b, &function->impl->body);
883 nir_metadata_preserve(function->impl, nir_metadata_block_index |
884 nir_metadata_dominance);
885
886 if (opt_if_cf_list(&b, &function->impl->body)) {
887 nir_metadata_preserve(function->impl, nir_metadata_none);
888
889 /* If that made progress, we're no longer really in SSA form. We
890 * need to convert registers back into SSA defs and clean up SSA defs
891 * that don't dominate their uses.
892 */
893 nir_lower_regs_to_ssa_impl(function->impl);
894
895 progress = true;
896 } else {
897 #ifndef NDEBUG
898 function->impl->valid_metadata &= ~nir_metadata_not_properly_reset;
899 #endif
900 }
901 }
902
903 return progress;
904 }