diff --git a/.pick_status.json b/.pick_status.json index ec308db527f..fe611b0f2da 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -54,7 +54,7 @@ "description": "nir/cf: have nir_remove_after_cf_node remove phis at the start too", "nominated": true, "nomination_type": 4, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": null, "notes": null diff --git a/src/compiler/nir/nir_control_flow.c b/src/compiler/nir/nir_control_flow.c index 41c1224515b..9e3099e7973 100644 --- a/src/compiler/nir/nir_control_flow.c +++ b/src/compiler/nir/nir_control_flow.c @@ -861,6 +861,28 @@ nir_cf_delete(nir_cf_list *cf_list) } } +void +nir_remove_after_cf_node(nir_cf_node *node) +{ + nir_cf_node *end = node; + while (!nir_cf_node_is_last(end)) + end = nir_cf_node_next(end); + + nir_cursor begin = nir_after_cf_node(node); + if (begin.option == nir_cursor_before_block) { + /* nir_cf_extract() would ignore these phis */ + nir_function_impl *impl = nir_cf_node_get_function(node); + nir_foreach_phi_safe(phi, begin.block) { + replace_ssa_def_uses(&phi->def, impl); + nir_instr_remove_v(&phi->instr); + } + } + + nir_cf_list list; + nir_cf_extract(&list, begin, nir_after_cf_node(end)); + nir_cf_delete(&list); +} + struct block_index { nir_block *block; uint32_t index; diff --git a/src/compiler/nir/nir_control_flow.h b/src/compiler/nir/nir_control_flow.h index 49f17c9c161..ac7444cb368 100644 --- a/src/compiler/nir/nir_control_flow.h +++ b/src/compiler/nir/nir_control_flow.h @@ -171,17 +171,8 @@ nir_cf_node_remove(nir_cf_node *node) nir_cf_delete(&list); } -static inline void -nir_remove_after_cf_node(nir_cf_node *node) -{ - nir_cf_node *end = node; - while (!nir_cf_node_is_last(end)) - end = nir_cf_node_next(end); - - nir_cf_list list; - nir_cf_extract(&list, nir_after_cf_node(node), nir_after_cf_node(end)); - nir_cf_delete(&list); -} +/** removes instructions after a control flow node, also removing any phis immediately after it */ +void nir_remove_after_cf_node(nir_cf_node *node); /** inserts undef phi sources from predcessor into phis of the block */ void nir_insert_phi_undef(nir_block *block, nir_block *pred); diff --git a/src/compiler/nir/tests/dce_tests.cpp b/src/compiler/nir/tests/dce_tests.cpp index 1aecc0ea984..25eb4d64147 100644 --- a/src/compiler/nir/tests/dce_tests.cpp +++ b/src/compiler/nir/tests/dce_tests.cpp @@ -137,3 +137,49 @@ TEST_F(nir_opt_dead_cf_test, jump_before_constant_if) nir_validate_shader(b->shader, NULL); } + +TEST_F(nir_opt_dead_cf_test, unreachable_phi) +{ + /* + * Test that nir_opt_dead_cf/nir_remove_after_cf_node removes phis at the start of dead code. + * + * block b0: // preds: + * 32 %0 = deref_var &cond (shader_in bool) + * 1 %1 = @load_deref (%0) (access=none) + * // succs: b1 b2 + * if %1 { + * block b1:// preds: b0 + * return + * // succs: b4 + * } else { + * block b2:// preds: b0 + * return + * // succs: b4 + * } + * block b3: // preds: + * 32 %2 = phi + * 32 %3 = deref_var &out (shader_out int) + * @store_deref (%3, %2) (wrmask=x, access=none) + * // succs: b4 + * block b4: + */ + nir_variable *cond = nir_variable_create(b->shader, nir_var_shader_in, glsl_bool_type(), "cond"); + nir_variable *var = nir_variable_create(b->shader, nir_var_shader_out, glsl_int_type(), "out"); + + nir_push_if(b, nir_load_var(b, cond)); + nir_jump(b, nir_jump_return); + nir_push_else(b, NULL); + nir_jump(b, nir_jump_return); + nir_pop_if(b, NULL); + + nir_phi_instr *phi = nir_phi_instr_create(b->shader); + nir_def_init(&phi->instr, &phi->def, 1, 32); + nir_builder_instr_insert(b, &phi->instr); + nir_store_var(b, var, &phi->def, 0x1); + + ASSERT_TRUE(nir_opt_dead_cf(b->shader)); + nir_validate_shader(b->shader, NULL); + + ASSERT_TRUE(exec_list_is_empty(&nir_impl_last_block(b->impl)->instr_list)); + ASSERT_FALSE(nir_opt_dead_cf(b->shader)); +}