+process_loops(nir_shader *sh, nir_cf_node *cf_node, bool *has_nested_loop_out,
+ bool *unrolled_this_block);
+
+static bool
+process_loops_in_block(nir_shader *sh, struct exec_list *block,
+ bool *has_nested_loop_out)
+{
+ /* We try to unroll as many loops in one pass as possible.
+ * E.g. we can safely unroll both loops in this block:
+ *
+ * if (...) {
+ * loop {...}
+ * }
+ *
+ * if (...) {
+ * loop {...}
+ * }
+ *
+ * Unrolling one loop doesn't affect the other one.
+ *
+ * On the other hand for block with:
+ *
+ * loop {...}
+ * ...
+ * loop {...}
+ *
+ * It is unsafe to unroll both loops in one pass without taking
+ * complicating precautions, since the structure of the block would
+ * change after unrolling the first loop. So in such a case we leave
+ * the second loop for the next iteration of unrolling to handle.
+ */
+
+ bool progress = false;
+ bool unrolled_this_block = false;
+
+ foreach_list_typed(nir_cf_node, nested_node, node, block) {
+ if (process_loops(sh, nested_node,
+ has_nested_loop_out, &unrolled_this_block)) {
+ progress = true;
+
+ /* If current node is unrolled we could not safely continue
+ * our iteration since we don't know the next node
+ * and it's hard to guarantee that we won't end up unrolling
+ * inner loop of the currently unrolled one, if such exists.
+ */
+ if (unrolled_this_block) {
+ break;
+ }
+ }
+ }
+
+ return progress;
+}
+
+static bool
+process_loops(nir_shader *sh, nir_cf_node *cf_node, bool *has_nested_loop_out,
+ bool *unrolled_this_block)