lima/ppir: add control flow support
authorVasily Khoruzhick <anarsoul@gmail.com>
Mon, 19 Aug 2019 06:37:23 +0000 (23:37 -0700)
committerVasily Khoruzhick <anarsoul@gmail.com>
Sat, 24 Aug 2019 15:17:31 +0000 (08:17 -0700)
This commit adds support for nir_jump_instr, if and loop
nir_cf_nodes.

Tested-by: Andreas Baierl <ichgeh@imkreisrum.de>
Reviewed-by: Qiang Yu <yuq825@gmail.com>
Reviewed-by: Erico Nunes <nunes.erico@gmail.com>
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
src/gallium/drivers/lima/ir/pp/codegen.c
src/gallium/drivers/lima/ir/pp/instr.c
src/gallium/drivers/lima/ir/pp/lower.c
src/gallium/drivers/lima/ir/pp/nir.c
src/gallium/drivers/lima/ir/pp/node.c
src/gallium/drivers/lima/ir/pp/ppir.h

index 4b1c48dffa3b0d605242fabd4f870d6e477e92bf..f08f83a9f4376728ea15060baa0c9000ebcc2e31 100644 (file)
@@ -558,6 +558,7 @@ static void ppir_codegen_encode_branch(ppir_node *node, void *code)
    ppir_codegen_field_branch *b = code;
    ppir_branch_node *branch;
    ppir_instr *target_instr;
+   ppir_block *target;
    if (node->op == ppir_op_discard) {
       ppir_codegen_encode_discard(node, code);
       return;
@@ -586,7 +587,16 @@ static void ppir_codegen_encode_branch(ppir_node *node, void *code)
       assert(false);
    }
 
-   target_instr = list_first_entry(&branch->target->instr_list, ppir_instr, list);
+   target = branch->target;
+   while (list_empty(&target->instr_list)) {
+      if (!target->list.next)
+         break;
+      target = LIST_ENTRY(ppir_block, target->list.next, list);
+   }
+
+   assert(!list_empty(&target->instr_list));
+
+   target_instr = list_first_entry(&target->instr_list, ppir_instr, list);
    b->branch.target = target_instr->offset - node->instr->offset;
    b->branch.next_count = target_instr->encode_size;
 }
index 474f9ca8cab3a463b0583ba3e2d78ba0a3eabd45..74b6e5fbaea6761dd70a8eb99d2bcab42884c3c6 100644 (file)
@@ -273,6 +273,7 @@ void ppir_instr_print_list(ppir_compiler *comp)
    printf("const0|1\n");
 
    list_for_each_entry(ppir_block, block, &comp->block_list, list) {
+      printf("-------block %3d-------\n", block->index);
       list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
          printf("%c%03d: ", instr->is_end ? '*' : ' ', instr->index);
          for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++) {
@@ -291,8 +292,8 @@ void ppir_instr_print_list(ppir_compiler *comp)
          }
          printf("\n");
       }
-      printf("------------------------\n");
    }
+   printf("===========================\n");
 }
 
 static void ppir_instr_print_sub(ppir_instr *instr)
@@ -325,12 +326,13 @@ void ppir_instr_print_dep(ppir_compiler *comp)
 
    printf("======ppir instr depend======\n");
    list_for_each_entry(ppir_block, block, &comp->block_list, list) {
+      printf("-------block %3d-------\n", block->index);
       list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
          if (ppir_instr_is_root(instr)) {
             ppir_instr_print_sub(instr);
             printf("\n");
          }
       }
-      printf("------------------------\n");
    }
+   printf("=============================\n");
 }
index cd175cc0879bb7c0d650dbefc856fb5685d5e942..5aca32e683e1622fbe5e792e93e4a7865ef4bef3 100644 (file)
@@ -227,22 +227,20 @@ static bool ppir_lower_select(ppir_block *block, ppir_node *node)
    move_dest->pipeline = ppir_pipeline_reg_fmul;
    move_dest->write_mask = 1;
 
-   ppir_node_foreach_pred(node, dep) {
-      ppir_node *pred = dep->pred;
-      ppir_dest *dest = ppir_node_get_dest(pred);
-      if (ppir_node_target_equal(alu->src, dest)) {
-         ppir_node_replace_pred(dep, move);
-         ppir_node_add_dep(move, pred);
-      }
-   }
+   ppir_node *pred = alu->src[0].node;
+   ppir_dep *dep = ppir_dep_for_pred(node, pred);
+   if (dep)
+      ppir_node_replace_pred(dep, move);
+   else
+      ppir_node_add_dep(node, move);
 
-   /* move must be the first pred of select node which make sure
-    * the float mul slot is free when node to instr
-    */
-   assert(ppir_node_first_pred(node) == move);
+   /* pred can be a register */
+   if (pred)
+      ppir_node_add_dep(move, pred);
 
    src->swizzle[0] = 0;
    ppir_node_target_assign(alu->src, move);
+
    return true;
 }
 
index 831c50b3cd039e4a7d872735daff70272e09edd1..4852e55a8b6f6ac72a0cb312dcf6afe83a6e0a16 100644 (file)
@@ -463,8 +463,39 @@ static ppir_block *ppir_get_block(ppir_compiler *comp, nir_block *nblock)
 
 static ppir_node *ppir_emit_jump(ppir_block *block, nir_instr *ni)
 {
-   ppir_error("nir_jump_instr not support\n");
-   return NULL;
+   ppir_node *node;
+   ppir_compiler *comp = block->comp;
+   ppir_branch_node *branch;
+   ppir_block *jump_block;
+   nir_jump_instr *jump = nir_instr_as_jump(ni);
+
+   switch (jump->type) {
+   case nir_jump_break: {
+      assert(comp->current_block->successors[0]);
+      assert(!comp->current_block->successors[1]);
+      jump_block = comp->current_block->successors[0];
+   }
+   break;
+   case nir_jump_continue:
+      jump_block = comp->loop_cont_block;
+   break;
+   default:
+      ppir_error("nir_jump_instr not support\n");
+      return NULL;
+   }
+
+   assert(jump_block != NULL);
+
+   node = ppir_node_create(block, ppir_op_branch, -1, 0);
+   if (!node)
+      return NULL;
+   branch = ppir_node_to_branch(node);
+
+   /* Unconditional */
+   branch->num_src = 0;
+   branch->target = jump_block;
+
+   return node;
 }
 
 static ppir_node *(*ppir_emit_instr[nir_instr_type_phi])(ppir_block *, nir_instr *) = {
@@ -494,6 +525,8 @@ static bool ppir_emit_block(ppir_compiler *comp, nir_block *nblock)
 {
    ppir_block *block = ppir_get_block(comp, nblock);
 
+   comp->current_block = block;
+
    list_addtail(&block->list, &comp->block_list);
 
    nir_foreach_instr(instr, nblock) {
@@ -508,16 +541,99 @@ static bool ppir_emit_block(ppir_compiler *comp, nir_block *nblock)
    return true;
 }
 
-static bool ppir_emit_if(ppir_compiler *comp, nir_if *nif)
+static bool ppir_emit_cf_list(ppir_compiler *comp, struct exec_list *list);
+
+static bool ppir_emit_if(ppir_compiler *comp, nir_if *if_stmt)
 {
-   ppir_error("if nir_cf_node not support\n");
-   return false;
+   ppir_node *node;
+   ppir_branch_node *else_branch, *after_branch;
+   nir_block *nir_else_block = nir_if_first_else_block(if_stmt);
+   bool empty_else_block =
+      (nir_else_block == nir_if_last_else_block(if_stmt) &&
+      exec_list_is_empty(&nir_else_block->instr_list));
+   ppir_block *block = comp->current_block;
+
+   node = ppir_node_create(block, ppir_op_branch, -1, 0);
+   if (!node)
+      return false;
+   else_branch = ppir_node_to_branch(node);
+   ppir_node_add_src(block->comp, node, &else_branch->src[0],
+                     &if_stmt->condition, 1);
+   else_branch->num_src = 1;
+   /* Negate condition to minimize branching. We're generating following:
+    * current_block: { ...; if (!statement) branch else_block; }
+    * then_block: { ...; branch after_block; }
+    * else_block: { ... }
+    * after_block: { ... }
+    *
+    * or if else list is empty:
+    * block: { if (!statement) branch else_block; }
+    * then_block: { ... }
+    * else_block: after_block: { ... }
+    */
+   else_branch->negate = true;
+   list_addtail(&else_branch->node.list, &block->node_list);
+
+   ppir_emit_cf_list(comp, &if_stmt->then_list);
+   if (empty_else_block) {
+      nir_block *nblock = nir_if_last_else_block(if_stmt);
+      assert(nblock->successors[0]);
+      assert(!nblock->successors[1]);
+      else_branch->target = ppir_get_block(comp, nblock->successors[0]);
+      /* Add empty else block to the list */
+      list_addtail(&block->successors[1]->list, &comp->block_list);
+      return true;
+   }
+
+   else_branch->target = ppir_get_block(comp, nir_if_first_else_block(if_stmt));
+
+   nir_block *last_then_block = nir_if_last_then_block(if_stmt);
+   assert(last_then_block->successors[0]);
+   assert(!last_then_block->successors[1]);
+   block = ppir_get_block(comp, last_then_block);
+   node = ppir_node_create(block, ppir_op_branch, -1, 0);
+   if (!node)
+      return false;
+   after_branch = ppir_node_to_branch(node);
+   /* Unconditional */
+   after_branch->num_src = 0;
+   after_branch->target = ppir_get_block(comp, last_then_block->successors[0]);
+   /* Target should be after_block, will fixup later */
+   list_addtail(&after_branch->node.list, &block->node_list);
+
+   ppir_emit_cf_list(comp, &if_stmt->else_list);
+
+   return true;
 }
 
 static bool ppir_emit_loop(ppir_compiler *comp, nir_loop *nloop)
 {
-   ppir_error("loop nir_cf_node not support\n");
-   return false;
+   ppir_block *save_loop_cont_block = comp->loop_cont_block;
+   ppir_block *block;
+   ppir_branch_node *loop_branch;
+   nir_block *loop_last_block;
+   ppir_node *node;
+
+   comp->loop_cont_block = ppir_get_block(comp, nir_loop_first_block(nloop));
+
+   ppir_emit_cf_list(comp, &nloop->body);
+
+   loop_last_block = nir_loop_last_block(nloop);
+   block = ppir_get_block(comp, loop_last_block);
+   node = ppir_node_create(block, ppir_op_branch, -1, 0);
+   if (!node)
+      return false;
+   loop_branch = ppir_node_to_branch(node);
+   /* Unconditional */
+   loop_branch->num_src = 0;
+   loop_branch->target = comp->loop_cont_block;
+   list_addtail(&loop_branch->node.list, &block->node_list);
+
+   comp->loop_cont_block = save_loop_cont_block;
+
+   comp->num_loops++;
+
+   return true;
 }
 
 static bool ppir_emit_function(ppir_compiler *comp, nir_function_impl *nfunc)
index 59635df3cdf4c2a4289f7a4c72b74f49d560147b..db141cac5c17bc2508a278ea00c697937a251c1b 100644 (file)
@@ -469,6 +469,21 @@ void ppir_node_replace_pred(ppir_dep *dep, ppir_node *new_pred)
    list_addtail(&dep->succ_link, &new_pred->succ_list);
 }
 
+ppir_dep *ppir_dep_for_pred(ppir_node *node, ppir_node *pred)
+{
+   if (!pred)
+      return NULL;
+
+   if (node->block != pred->block)
+      return NULL;
+
+   ppir_node_foreach_pred(node, dep) {
+      if (dep->pred == pred)
+         return dep;
+   }
+   return NULL;
+}
+
 void ppir_node_replace_all_succ(ppir_node *dst, ppir_node *src)
 {
    ppir_node_foreach_succ_safe(src, dep) {
@@ -573,7 +588,7 @@ void ppir_node_print_prog(ppir_compiler *comp)
 
    printf("========prog========\n");
    list_for_each_entry(ppir_block, block, &comp->block_list, list) {
-      printf("-------block------\n");
+      printf("-------block %3d-------\n", block->index);
       list_for_each_entry(ppir_node, node, &block->node_list, list) {
          if (ppir_node_is_root(node))
             ppir_node_print_node(node, 0);
index db8087ede623486ffa97eb878e78f5eb234e3992..462cd93538a2f5556f94eae468bc19d880c4cf2f 100644 (file)
@@ -369,6 +369,9 @@ typedef struct ppir_compiler {
    int num_fills;
 
    ppir_block *discard_block;
+   ppir_block *current_block;
+   ppir_block *loop_break_block;
+   ppir_block *loop_cont_block;
 } ppir_compiler;
 
 void *ppir_node_create(ppir_block *block, ppir_op op, int index, unsigned mask);
@@ -379,6 +382,7 @@ void ppir_node_print_prog(ppir_compiler *comp);
 void ppir_node_replace_child(ppir_node *parent, ppir_node *old_child, ppir_node *new_child);
 void ppir_node_replace_all_succ(ppir_node *dst, ppir_node *src);
 void ppir_node_replace_pred(ppir_dep *dep, ppir_node *new_pred);
+ppir_dep *ppir_dep_for_pred(ppir_node *node, ppir_node *pred);
 ppir_node *ppir_node_clone(ppir_block *block, ppir_node *node);
 
 static inline bool ppir_node_is_root(ppir_node *node)