zink/spirv: implement if-statements

Acked-by: Jordan Justen <jordan.l.justen@intel.com>
This commit is contained in:
Erik Faye-Lund 2019-03-22 15:10:25 +01:00
parent 8bbf86e7bc
commit 11ad9bfc35
3 changed files with 141 additions and 2 deletions

View File

@ -1142,13 +1142,33 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
static void
start_block(struct ntv_context *ctx, SpvId label)
{
assert(!ctx->block_started);
/* terminate previous block if needed */
if (ctx->block_started)
spirv_builder_emit_branch(&ctx->builder, label);
/* start new block */
spirv_builder_label(&ctx->builder, label);
ctx->block_started = true;
}
static void
branch(struct ntv_context *ctx, SpvId label)
{
assert(ctx->block_started);
spirv_builder_emit_branch(&ctx->builder, label);
ctx->block_started = false;
}
static void
branch_conditional(struct ntv_context *ctx, SpvId condition, SpvId then_id,
SpvId else_id)
{
assert(ctx->block_started);
spirv_builder_emit_branch_conditional(&ctx->builder, condition,
then_id, else_id);
ctx->block_started = false;
}
static void
emit_block(struct ntv_context *ctx, struct nir_block *block)
{
@ -1189,6 +1209,50 @@ emit_block(struct ntv_context *ctx, struct nir_block *block)
}
}
static void
emit_cf_list(struct ntv_context *ctx, struct exec_list *list);
static SpvId
get_src_bool(struct ntv_context *ctx, nir_src *src)
{
SpvId def = get_src_uint(ctx, src);
assert(nir_src_bit_size(*src) == 32);
unsigned num_components = nir_src_num_components(*src);
return uvec_to_bvec(ctx, def, num_components);
}
static void
emit_if(struct ntv_context *ctx, nir_if *if_stmt)
{
SpvId condition = get_src_bool(ctx, &if_stmt->condition);
SpvId header_id = spirv_builder_new_id(&ctx->builder);
SpvId then_id = block_label(ctx, nir_if_first_then_block(if_stmt));
SpvId endif_id = spirv_builder_new_id(&ctx->builder);
SpvId else_id = endif_id;
bool has_else = !exec_list_is_empty(&if_stmt->else_list);
if (has_else) {
assert(nir_if_first_else_block(if_stmt)->index < ctx->num_blocks);
else_id = block_label(ctx, nir_if_first_else_block(if_stmt));
}
/* create a header-block */
start_block(ctx, header_id);
spirv_builder_emit_selection_merge(&ctx->builder, endif_id,
SpvSelectionControlMaskNone);
branch_conditional(ctx, condition, then_id, else_id);
emit_cf_list(ctx, &if_stmt->then_list);
if (has_else) {
branch(ctx, endif_id);
emit_cf_list(ctx, &if_stmt->else_list);
}
start_block(ctx, endif_id);
}
static void
emit_cf_list(struct ntv_context *ctx, struct exec_list *list)
{
@ -1199,7 +1263,7 @@ emit_cf_list(struct ntv_context *ctx, struct exec_list *list)
break;
case nir_cf_node_if:
unreachable("nir_cf_node_if not supported");
emit_if(ctx, nir_cf_node_as_if(node));
break;
case nir_cf_node_loop:

View File

@ -432,6 +432,61 @@ spirv_builder_emit_vector_shuffle(struct spirv_builder *b, SpvId result_type,
return result;
}
void
spirv_builder_emit_branch(struct spirv_builder *b, SpvId label)
{
spirv_buffer_prepare(&b->instructions, 2);
spirv_buffer_emit_word(&b->instructions, SpvOpBranch | (2 << 16));
spirv_buffer_emit_word(&b->instructions, label);
}
void
spirv_builder_emit_selection_merge(struct spirv_builder *b, SpvId merge_block,
SpvSelectionControlMask selection_control)
{
spirv_buffer_prepare(&b->instructions, 3);
spirv_buffer_emit_word(&b->instructions, SpvOpSelectionMerge | (3 << 16));
spirv_buffer_emit_word(&b->instructions, merge_block);
spirv_buffer_emit_word(&b->instructions, selection_control);
}
void
spirv_builder_emit_branch_conditional(struct spirv_builder *b, SpvId condition,
SpvId true_label, SpvId false_label)
{
spirv_buffer_prepare(&b->instructions, 4);
spirv_buffer_emit_word(&b->instructions, SpvOpBranchConditional | (4 << 16));
spirv_buffer_emit_word(&b->instructions, condition);
spirv_buffer_emit_word(&b->instructions, true_label);
spirv_buffer_emit_word(&b->instructions, false_label);
}
SpvId
spirv_builder_emit_phi(struct spirv_builder *b, SpvId result_type,
size_t num_vars, size_t *position)
{
SpvId result = spirv_builder_new_id(b);
assert(num_vars > 0);
int words = 3 + 2 * num_vars;
spirv_buffer_prepare(&b->instructions, words);
spirv_buffer_emit_word(&b->instructions, SpvOpPhi | (words << 16));
spirv_buffer_emit_word(&b->instructions, result_type);
spirv_buffer_emit_word(&b->instructions, result);
*position = b->instructions.num_words;
for (int i = 0; i < 2 * num_vars; ++i)
spirv_buffer_emit_word(&b->instructions, 0);
return result;
}
void
spirv_builder_set_phi_operand(struct spirv_builder *b, size_t position,
size_t index, SpvId variable, SpvId parent)
{
b->instructions.words[position + index * 2 + 0] = variable;
b->instructions.words[position + index * 2 + 1] = parent;
}
SpvId
spirv_builder_emit_image_sample_implicit_lod(struct spirv_builder *b,
SpvId result_type,

View File

@ -175,6 +175,26 @@ spirv_builder_emit_vector_shuffle(struct spirv_builder *b, SpvId result_type,
const uint32_t components[],
size_t num_components);
void
spirv_builder_emit_branch(struct spirv_builder *b, SpvId label);
void
spirv_builder_emit_selection_merge(struct spirv_builder *b, SpvId merge_block,
SpvSelectionControlMask selection_control);
void
spirv_builder_emit_branch_conditional(struct spirv_builder *b, SpvId condition,
SpvId true_label, SpvId false_label);
SpvId
spirv_builder_emit_phi(struct spirv_builder *b, SpvId result_type,
size_t num_vars, size_t *position);
void
spirv_builder_set_phi_operand(struct spirv_builder *b, size_t position,
size_t index, SpvId variable, SpvId parent);
SpvId
spirv_builder_emit_image_sample_implicit_lod(struct spirv_builder *b,
SpvId result_type,