nir: prevent peephole from generating invalid NIR

We can't append instructions following a return/halt instruction
because the control flow helpers will modify the successor of the
block containing the return/halt. And the NIR validator enforces that
the return/halt must have the end of the function as successor.

This tends to happen following lower_shader_calls lowering which
inserts halts. This probably doesn't prevent the optimization, it'll
just happen in one of the return shaders after the halt has been
removed.

v2: Move prev block ending check earlier in the function (Daniel)

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Daniel Schürmann <daniel@schuermann.dev>
Cc: mesa-stable
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12506>
This commit is contained in:
Lionel Landwerlin 2021-08-23 16:45:20 +03:00 committed by Marge Bot
parent e0a703af11
commit a13e79843e
2 changed files with 26 additions and 2 deletions

View file

@ -2938,6 +2938,21 @@ nir_block_ends_in_jump(nir_block *block)
nir_block_last_instr(block)->type == nir_instr_type_jump;
}
static inline bool
nir_block_ends_in_return_or_halt(nir_block *block)
{
if (exec_list_is_empty(&block->instr_list))
return false;
nir_instr *instr = nir_block_last_instr(block);
if (instr->type != nir_instr_type_jump)
return false;
nir_jump_instr *jump_instr = nir_instr_as_jump(instr);
return jump_instr->type == nir_jump_return ||
jump_instr->type == nir_jump_halt;
}
static inline bool
nir_block_ends_in_break(nir_block *block)
{

View file

@ -381,6 +381,17 @@ nir_opt_peephole_select_block(nir_block *block, nir_shader *shader,
if (prev_node->type != nir_cf_node_if)
return false;
nir_block *prev_block = nir_cf_node_as_block(nir_cf_node_prev(prev_node));
/* If the last instruction before this if/else block is a jump, we can't
* append stuff after it because it would break a bunch of assumption about
* control flow (nir_validate expects the successor of a return/halt jump
* to be the end of the function, which might not match the successor of
* the if/else blocks).
*/
if (nir_block_ends_in_return_or_halt(prev_block))
return false;
nir_if *if_stmt = nir_cf_node_as_if(prev_node);
/* first, try to collapse the if */
@ -422,8 +433,6 @@ nir_opt_peephole_select_block(nir_block *block, nir_shader *shader,
* selects.
*/
nir_block *prev_block = nir_cf_node_as_block(nir_cf_node_prev(prev_node));
/* First, we move the remaining instructions from the blocks to the
* block before. We have already guaranteed that this is safe by
* calling block_check_for_allowed_instrs()