From 11ad9bfc35cd0c300fcf7be6133a04beba409895 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Fri, 22 Mar 2019 15:10:25 +0100 Subject: [PATCH] zink/spirv: implement if-statements Acked-by: Jordan Justen --- .../drivers/zink/nir_to_spirv/nir_to_spirv.c | 68 ++++++++++++++++++- .../drivers/zink/nir_to_spirv/spirv_builder.c | 55 +++++++++++++++ .../drivers/zink/nir_to_spirv/spirv_builder.h | 20 ++++++ 3 files changed, 141 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c index 099f78a1255..9fc7aa94cd2 100644 --- a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c +++ b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c @@ -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: diff --git a/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.c b/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.c index daae3458dcf..1a02ab0fe09 100644 --- a/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.c +++ b/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.c @@ -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, diff --git a/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.h b/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.h index ddc4bbf4328..2fecaf445f2 100644 --- a/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.h +++ b/src/gallium/drivers/zink/nir_to_spirv/spirv_builder.h @@ -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, -- 2.30.2