nir/lower_shader_calls: wrap only jumps rather than entire code blocks
authorLionel Landwerlin <lionel.g.landwerlin@intel.com>
Wed, 16 Nov 2022 15:34:08 +0000 (17:34 +0200)
committerMarge Bot <emma+marge@anholt.net>
Sat, 19 Nov 2022 10:53:18 +0000 (10:53 +0000)
Moving entire chunks of code into a dummy if block is causing issues
in some situations. To work around the issue that we tried to fix in
35d82ecf1e ("nir/lower_shader_calls: put inserted instructions into a
dummy block") which is that we cannot cut and past a block of
instruction that ends with a jump if there are more instruction behind
where we're going to past. We can instead just wraps the jumps into
dummy if blocks.

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Cc: mesa-stable
Reviewed-by: Konstantin Seurer <konstantin.seurer@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19820>

src/compiler/nir/nir_lower_shader_calls.c

index 8c4c4ca..433ce50 100644 (file)
@@ -1185,11 +1185,42 @@ found_resume:
    return true;
 }
 
+static bool
+wrap_jump_instr(nir_builder *b, nir_instr *instr, void *data)
+{
+   if (instr->type != nir_instr_type_jump)
+      return false;
+
+   b->cursor = nir_before_instr(instr);
+
+   nir_if *_if = nir_push_if(b, nir_imm_true(b));
+   nir_pop_if(b, NULL);
+
+   nir_cf_list cf_list;
+   nir_cf_extract(&cf_list, nir_before_instr(instr), nir_after_instr(instr));
+   nir_cf_reinsert(&cf_list, nir_before_block(nir_if_first_then_block(_if)));
+
+   return true;
+}
+
+/* This pass wraps jump instructions in a dummy if block so that when
+ * flatten_resume_if_ladder() does its job, it doesn't move a jump instruction
+ * directly in front of another instruction which the NIR control flow helpers
+ * do not allow.
+ */
+static bool
+wrap_jumps(nir_shader *shader)
+{
+   return nir_shader_instructions_pass(shader, wrap_jump_instr,
+                                       nir_metadata_none, NULL);
+}
+
 static nir_instr *
 lower_resume(nir_shader *shader, int call_idx)
 {
-   nir_function_impl *impl = nir_shader_get_entrypoint(shader);
+   wrap_jumps(shader);
 
+   nir_function_impl *impl = nir_shader_get_entrypoint(shader);
    nir_instr *resume_instr = find_resume_instr(impl, call_idx);
 
    if (duplicate_loop_bodies(impl, resume_instr)) {