case nir_jump_return:
unreachable("All returns shouold be lowered\n");
+ break;
+
+ case nir_jump_goto:
+ case nir_jump_goto_if:
+ unreachable("not supported\n");
+ break;
}
}
{
nir_jump_instr *instr = ralloc(shader, nir_jump_instr);
instr_init(&instr->instr, nir_instr_type_jump);
+ src_init(&instr->condition);
instr->type = type;
+ instr->target = NULL;
+ instr->else_target = NULL;
return instr;
}
return true;
}
+static bool
+visit_jump_src(nir_jump_instr *instr, nir_foreach_src_cb cb, void *state)
+{
+ if (instr->type != nir_jump_goto_if)
+ return true;
+
+ return visit_src(&instr->condition, cb, state);
+}
+
typedef struct {
void *state;
nir_foreach_src_cb cb;
return false;
break;
case nir_instr_type_jump:
+ return visit_jump_src(nir_instr_as_jump(instr), cb, state);
case nir_instr_type_ssa_undef:
return true;
* NIR loop is implemented as "while (1) { body }".
*/
nir_jump_continue,
+
+ /** Jumps for unstructured CFG.
+ *
+ * As within an unstructured CFG we can't rely on block ordering we need to
+ * place explicit jumps at the end of every block.
+ */
+ nir_jump_goto,
+ nir_jump_goto_if,
} nir_jump_type;
typedef struct {
nir_instr instr;
nir_jump_type type;
+ nir_src condition;
+ struct nir_block *target;
+ struct nir_block *else_target;
} nir_jump_instr;
/* creates a new SSA variable in an undefined state */
static inline void
nir_jump(nir_builder *build, nir_jump_type jump_type)
{
+ assert(jump_type != nir_jump_goto && jump_type != nir_jump_goto_if);
nir_jump_instr *jump = nir_jump_instr_create(build->shader, jump_type);
nir_builder_instr_insert(build, &jump->instr);
}
+static inline void
+nir_goto(nir_builder *build, struct nir_block *target)
+{
+ assert(!build->impl->structured);
+ nir_jump_instr *jump = nir_jump_instr_create(build->shader, nir_jump_goto);
+ jump->target = target;
+ nir_builder_instr_insert(build, &jump->instr);
+}
+
+static inline void
+nir_goto_if(nir_builder *build, struct nir_block *target, nir_src cond,
+ struct nir_block *else_target)
+{
+ assert(!build->impl->structured);
+ nir_jump_instr *jump = nir_jump_instr_create(build->shader, nir_jump_goto_if);
+ jump->condition = cond;
+ jump->target = target;
+ jump->else_target = else_target;
+ nir_builder_instr_insert(build, &jump->instr);
+}
+
static inline nir_ssa_def *
nir_compare_func(nir_builder *b, enum compare_func func,
nir_ssa_def *src0, nir_ssa_def *src1)
unlink_block_successors(block);
link_blocks(block, first_then_block, first_else_block);
- } else {
+ } else if (node->type == nir_cf_node_loop) {
/*
* For similar reasons as the corresponding case in
* link_non_block_to_block(), don't worry about if the loop header has
nir_block *first_else_block = nir_if_first_else_block(next_if);
link_blocks(block, first_then_block, first_else_block);
- } else {
+ } else if (next->type == nir_cf_node_loop) {
nir_loop *next_loop = nir_cf_node_as_loop(next);
nir_block *first_block = nir_loop_first_block(next_loop);
break;
}
+ case nir_jump_goto:
+ link_blocks(block, jump_instr->target, NULL);
+ break;
+
+ case nir_jump_goto_if:
+ link_blocks(block, jump_instr->else_target, jump_instr->target);
+ break;
+
default:
unreachable("Invalid jump type");
}
/* We need to walk the instructions and clean up defs/uses */
nir_foreach_instr_safe(instr, block) {
if (instr->type == nir_instr_type_jump) {
- nir_jump_type jump_type = nir_instr_as_jump(instr)->type;
- unlink_jump(block, jump_type, false);
+ nir_jump_instr *jump = nir_instr_as_jump(instr);
+ unlink_jump(block, jump->type, false);
+ if (jump->type == nir_jump_goto_if)
+ nir_instr_rewrite_src(instr, &jump->condition, NIR_SRC_INIT);
} else {
nir_foreach_ssa_def(instr, replace_ssa_def_uses, impl);
nir_instr_remove(instr);
return state->divergent_loop_break;
case nir_jump_return:
unreachable("NIR divergence analysis: Unsupported return instruction.");
+ break;
+ case nir_jump_goto:
+ case nir_jump_goto_if:
+ unreachable("NIR divergence analysis: Unsupported goto_if instruction.");
+ break;
}
return false;
}
case nir_jump_return:
fprintf(fp, "return");
break;
+
+ case nir_jump_goto:
+ fprintf(fp, "goto block_%u",
+ instr->target ? instr->target->index : -1);
+ break;
+
+ case nir_jump_goto_if:
+ fprintf(fp, "goto block_%u if ",
+ instr->target ? instr->target->index : -1);
+ print_src(&instr->condition, state);
+ fprintf(fp, " else block_%u",
+ instr->else_target ? instr->else_target->index : -1);
+ break;
}
}
case nir_jump_return:
validate_assert(state, block->successors[0] == state->impl->end_block);
validate_assert(state, block->successors[1] == NULL);
+ validate_assert(state, instr->target == NULL);
+ validate_assert(state, instr->else_target == NULL);
break;
case nir_jump_break:
validate_assert(state, block->successors[0] == after);
}
validate_assert(state, block->successors[1] == NULL);
+ validate_assert(state, instr->target == NULL);
+ validate_assert(state, instr->else_target == NULL);
break;
case nir_jump_continue:
validate_assert(state, block->successors[0] == first);
}
validate_assert(state, block->successors[1] == NULL);
+ validate_assert(state, instr->target == NULL);
+ validate_assert(state, instr->else_target == NULL);
+ break;
+
+ case nir_jump_goto:
+ validate_assert(state, !state->impl->structured);
+ validate_assert(state, instr->target == block->successors[0]);
+ validate_assert(state, instr->target != NULL);
+ validate_assert(state, instr->else_target == NULL);
+ break;
+
+ case nir_jump_goto_if:
+ validate_assert(state, !state->impl->structured);
+ validate_assert(state, instr->target == block->successors[1]);
+ validate_assert(state, instr->else_target == block->successors[0]);
+ validate_src(&instr->condition, state, 0, 1);
+ validate_assert(state, instr->target != NULL);
+ validate_assert(state, instr->else_target != NULL);
break;
default: