[Mesa-dev] [PATCH 18/21] etnaviv: nir: implement conditionals

Philipp Zabel p.zabel at pengutronix.de
Tue Jun 5 14:38:42 UTC 2018


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.zabel at pengutronix.de>
Signed-off-by: Michael Tretter <m.tretter at 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



More information about the mesa-dev mailing list