* block block_1:
* vec1 32 ssa_2 = phi block_0: ssa_0, block_7: ssa_5
* vec1 32 ssa_3 = phi block_0: ssa_0, block_7: ssa_1
- * if ssa_2 {
+ * if ssa_3 {
* block block_2:
* vec1 32 ssa_4 = load_const (0x00000001)
* vec1 32 ssa_5 = iadd ssa_2, ssa_4
* // Stuff from block 3
* loop {
* block block_1:
- * vec1 32 ssa_3 = phi block_0: ssa_0, block_7: ssa_1
+ * vec1 32 ssa_2 = phi block_0: ssa_0, block_7: ssa_5
* vec1 32 ssa_6 = load_const (0x00000004)
- * vec1 32 ssa_7 = ilt ssa_5, ssa_6
+ * vec1 32 ssa_7 = ilt ssa_2, ssa_6
* if ssa_7 {
* block block_5:
* } else {
nir_cf_reinsert(&header,
nir_after_block_before_jump(find_continue_block(loop)));
+ bool continue_list_jumps =
+ nir_block_ends_in_jump(exec_node_data(nir_block,
+ exec_list_get_tail(continue_list),
+ cf_node.node));
+
nir_cf_extract(&tmp, nir_before_cf_list(continue_list),
nir_after_cf_list(continue_list));
- /* Get continue block again as the previous reinsert might have removed the block. */
+ /* Get continue block again as the previous reinsert might have removed the
+ * block. Also, if both the continue list and the continue block ends in
+ * jump instructions, removes the jump from the latter, as it will not be
+ * executed if we insert the continue list before it. */
+
+ nir_block *continue_block = find_continue_block(loop);
+
+ if (continue_list_jumps) {
+ nir_instr *last_instr = nir_block_last_instr(continue_block);
+ if (last_instr && last_instr->type == nir_instr_type_jump)
+ nir_instr_remove(last_instr);
+ }
+
nir_cf_reinsert(&tmp,
- nir_after_block_before_jump(find_continue_block(loop)));
+ nir_after_block_before_jump(continue_block));
nir_cf_node_remove(&nif->cf_node);
*
* Insert the new instruction at the end of the continue block.
*/
- b->cursor = nir_after_block(continue_block);
+ b->cursor = nir_after_block_before_jump(continue_block);
nir_ssa_def *const alu_copy =
clone_alu_and_replace_src_defs(b, alu, continue_srcs);
/* If both branches end in a continue do nothing, this should be handled
* by nir_opt_dead_cf().
*/
- if (then_ends_in_continue && else_ends_in_continue)
+ if ((then_ends_in_continue || nir_block_ends_in_break(then_block)) &&
+ (else_ends_in_continue || nir_block_ends_in_break(else_block)))
return false;
if (!then_ends_in_continue && !else_ends_in_continue)
nir_cf_list tmp;
nir_cf_extract(&tmp, nir_after_cf_node(if_node),
nir_after_block(last_block));
- if (then_ends_in_continue) {
- nir_cursor last_blk_cursor = nir_after_cf_list(&nif->else_list);
- nir_cf_reinsert(&tmp,
- nir_after_block_before_jump(last_blk_cursor.block));
- } else {
- nir_cursor last_blk_cursor = nir_after_cf_list(&nif->then_list);
- nir_cf_reinsert(&tmp,
- nir_after_block_before_jump(last_blk_cursor.block));
- }
+ if (then_ends_in_continue)
+ nir_cf_reinsert(&tmp, nir_after_cf_list(&nif->else_list));
+ else
+ nir_cf_reinsert(&tmp, nir_after_cf_list(&nif->then_list));
/* In order to avoid running nir_lower_regs_to_ssa_impl() every time an if
* opt makes progress we leave nir_opt_trivial_continues() to remove the