return progress;
}
+static void
+simple_merge_if(nir_if *dest_if, nir_if *src_if, bool dest_if_then,
+ bool src_if_then)
+{
+ /* Now merge the if branch */
+ nir_block *dest_blk = dest_if_then ? nir_if_last_then_block(dest_if)
+ : nir_if_last_else_block(dest_if);
+
+ struct exec_list *list = src_if_then ? &src_if->then_list
+ : &src_if->else_list;
+
+ nir_cf_list if_cf_list;
+ nir_cf_extract(&if_cf_list, nir_before_cf_list(list),
+ nir_after_cf_list(list));
+ nir_cf_reinsert(&if_cf_list, nir_after_block(dest_blk));
+}
+
+static bool
+opt_if_merge(nir_if *nif)
+{
+ bool progress = false;
+
+ nir_block *next_blk = nir_cf_node_cf_tree_next(&nif->cf_node);
+ if (next_blk && nif->condition.is_ssa) {
+ nir_if *next_if = nir_block_get_following_if(next_blk);
+ if (next_if && next_if->condition.is_ssa) {
+
+ /* Here we merge two consecutive ifs that have the same
+ * condition e.g:
+ *
+ * if ssa_12 {
+ * ...
+ * } else {
+ * ...
+ * }
+ * if ssa_12 {
+ * ...
+ * } else {
+ * ...
+ * }
+ *
+ * Note: This only merges if-statements when the block between them
+ * is empty. The reason we don't try to merge ifs that just have phis
+ * between them is because this can results in increased register
+ * pressure. For example when merging if ladders created by indirect
+ * indexing.
+ */
+ if (nif->condition.ssa == next_if->condition.ssa &&
+ exec_list_is_empty(&next_blk->instr_list)) {
+
+ simple_merge_if(nif, next_if, true, true);
+ simple_merge_if(nif, next_if, false, false);
+
+ nir_block *new_then_block = nir_if_last_then_block(nif);
+ nir_block *new_else_block = nir_if_last_else_block(nif);
+
+ nir_block *old_then_block = nir_if_last_then_block(next_if);
+ nir_block *old_else_block = nir_if_last_else_block(next_if);
+
+ /* Rewrite the predecessor block for any phis following the second
+ * if-statement.
+ */
+ rewrite_phi_predecessor_blocks(next_if, old_then_block,
+ old_else_block,
+ new_then_block,
+ new_else_block);
+
+ /* Move phis after merged if to avoid them being deleted when we
+ * remove the merged if-statement.
+ */
+ nir_block *after_next_if_block =
+ nir_cf_node_as_block(nir_cf_node_next(&next_if->cf_node));
+
+ nir_foreach_instr_safe(instr, after_next_if_block) {
+ if (instr->type != nir_instr_type_phi)
+ break;
+
+ exec_node_remove(&instr->node);
+ exec_list_push_tail(&next_blk->instr_list, &instr->node);
+ instr->block = next_blk;
+ }
+
+ nir_cf_node_remove(&next_if->cf_node);
+
+ progress = true;
+ }
+ }
+ }
+
+ return progress;
+}
+
static bool
opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)
{
progress |= opt_if_cf_list(b, &nif->then_list);
progress |= opt_if_cf_list(b, &nif->else_list);
progress |= opt_if_loop_terminator(nif);
+ progress |= opt_if_merge(nif);
progress |= opt_if_simplification(b, nif);
break;
}