Emit conditional branches for nir_cf_code_if blocks following a comparison operation. The NIR compiler does not assign registers to the comparison operations, and the emitter does not emit any instructions for them. Instead, the nir_cf_code_if blocks cause emission of a conditional branch instruction using the sources and condition flags from the preceding conditional operation.
Signed-off-by: Philipp Zabel <p.za...@pengutronix.de> Signed-off-by: Michael Tretter <m.tret...@pengutronix.de> --- .../drivers/etnaviv/etnaviv_compiler.c | 75 +++++++++++++++++++ src/gallium/drivers/etnaviv/etnaviv_nir.c | 18 +++++ 2 files changed, 93 insertions(+) diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.c b/src/gallium/drivers/etnaviv/etnaviv_compiler.c index b2499a7e2f6c..0db961c5a751 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_compiler.c +++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.c @@ -2162,6 +2162,12 @@ etna_emit_alu(struct etna_compile *c, nir_alu_instr *instr) .src[1] = src[1], }); break; + case nir_op_feq: + case nir_op_fne: + case nir_op_flt: + case nir_op_fge: + /* Nothing to do, will be handled by the following nir_if */ + break; default: BUG("Unhandled nir_alu_instr: %s\n", info->name); assert(0); @@ -2282,6 +2288,72 @@ etna_emit_block(struct etna_compile *c, nir_block *nblock) } } +static void etna_emit_cf_list(struct etna_compile *c, struct exec_list *list); + +static void +etna_emit_if(struct etna_compile *c, nir_if *nif) +{ + struct etna_inst_src src[3] = {}; + + assert(nif->condition.is_ssa); + + assert(nif->condition.ssa->parent_instr->type == nir_instr_type_alu); + nir_alu_instr *instr = nir_instr_as_alu(nif->condition.ssa->parent_instr); + + assert(instr->op == nir_op_fne || instr->op == nir_op_feq); + + translate_alu_sources(c, instr, src); + + /* The NIR layer should have taken care of this */ + assert(!etna_src_uniforms_conflict(src[0], src[1])); + + unsigned sp = c->frame_sp++; + struct etna_compile_frame *f = &c->frame_stack[sp]; + /* push IF to stack */ + f->type = ETNA_COMPILE_FRAME_IF; + /* create "else" label */ + f->lbl_else_idx = alloc_new_label(c); + f->lbl_endif_idx = -1; + + /* mark position in instruction stream of label reference so that it can be + * filled in in next pass */ + label_mark_use(c, f->lbl_else_idx); + + /* create conditional branch to else label if not src0 COND src1 */ + emit_inst(c, &(struct etna_inst){ + .opcode = INST_OPCODE_BRANCH, + .cond = (instr->op == nir_op_fne) ? INST_CONDITION_EQ : INST_CONDITION_NE, + .src[0] = src[0], + .src[1] = src[1], + /* imm is filled in later */ + }); + + etna_emit_cf_list(c, &nif->then_list); + + /* create "endif" label, and branch to endif label */ + f->lbl_endif_idx = alloc_new_label(c); + label_mark_use(c, f->lbl_endif_idx); + emit_inst(c, &(struct etna_inst) { + .opcode = INST_OPCODE_BRANCH, + .cond = INST_CONDITION_TRUE, + /* imm is filled in later */ + }); + + /* mark "else" label at this position in instruction stream */ + label_place(c, &c->labels[f->lbl_else_idx]); + + etna_emit_cf_list(c, &nif->else_list); + + assert(--c->frame_sp == sp); + + /* assign "endif" or "else" (if no ELSE) label to current position in + * instruction stream, pop IF */ + if (f->lbl_endif_idx != -1) + label_place(c, &c->labels[f->lbl_endif_idx]); + else + label_place(c, &c->labels[f->lbl_else_idx]); +} + static void etna_emit_cf_list(struct etna_compile *c, struct exec_list *list) { @@ -2290,6 +2362,9 @@ etna_emit_cf_list(struct etna_compile *c, struct exec_list *list) case nir_cf_node_block: etna_emit_block(c, nir_cf_node_as_block(node)); break; + case nir_cf_node_if: + etna_emit_if(c, nir_cf_node_as_if(node)); + break; default: BUG("Unhandled nir node type %d\n", node->type); assert(0); diff --git a/src/gallium/drivers/etnaviv/etnaviv_nir.c b/src/gallium/drivers/etnaviv/etnaviv_nir.c index af1684ed9091..d8bd282eaeca 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_nir.c +++ b/src/gallium/drivers/etnaviv/etnaviv_nir.c @@ -399,6 +399,20 @@ etna_fixup_tex(nir_shader *shader) } } +static bool +nir_op_is_comparison(nir_op op) +{ + switch (op) { + case nir_op_flt: + case nir_op_fge: + case nir_op_feq: + case nir_op_fne: + return true; + default: + return false; + } +} + /* Return the destination SSA if it should be replaced with a global register, * or NULL. */ @@ -423,6 +437,10 @@ etna_instr_replaceable_ssa_dest(nir_instr *instr) if (instr->type == nir_instr_type_alu) { nir_alu_instr *alu = nir_instr_as_alu(instr); + /* Comparisons will be turned into conditional jumps */ + if (nir_op_is_comparison(alu->op)) + return NULL; + return alu->dest.dest.is_ssa ? &alu->dest.dest.ssa : NULL; } -- 2.17.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev