nir/spirv: Move CF emit code into vtn_cfg.c
authorJason Ekstrand <jason.ekstrand@intel.com>
Tue, 29 Dec 2015 20:09:32 +0000 (12:09 -0800)
committerJason Ekstrand <jason.ekstrand@intel.com>
Tue, 29 Dec 2015 20:50:31 +0000 (12:50 -0800)
src/glsl/nir/spirv/spirv_to_nir.c
src/glsl/nir/spirv/vtn_cfg.c
src/glsl/nir/spirv/vtn_private.h

index 1539c750036cd378511065ceb395bb3592a190bc..4a90f1827cfd23fc509ffa827623f20924484be6 100644 (file)
@@ -1459,7 +1459,7 @@ static nir_ssa_def * vtn_vector_insert_dynamic(struct vtn_builder *b,
                                                nir_ssa_def *src,
                                                nir_ssa_def *insert,
                                                nir_ssa_def *index);
-static void
+void
 vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src,
                    nir_deref_var *dest, struct vtn_type *dest_type)
 {
@@ -3574,226 +3574,6 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
    return true;
 }
 
-/* XXX: This should go in nir_builder.h */
-static inline void
-nir_jump(nir_builder *build, nir_jump_type jump_type)
-{
-   nir_jump_instr *jump = nir_jump_instr_create(build->shader, jump_type);
-   nir_builder_instr_insert(build, &jump->instr);
-}
-
-static void
-vtn_emit_branch(struct vtn_builder *b, enum vtn_branch_type branch_type,
-                nir_variable *switch_fall_var, bool *has_switch_break)
-{
-   switch (branch_type) {
-   case vtn_branch_type_switch_break:
-      nir_store_var(&b->nb, switch_fall_var, nir_imm_int(&b->nb, NIR_FALSE), 1);
-      *has_switch_break = true;
-      break;
-   case vtn_branch_type_switch_fallthrough:
-      break; /* Nothing to do */
-   case vtn_branch_type_loop_break:
-      nir_jump(&b->nb, nir_jump_break);
-      break;
-   case vtn_branch_type_loop_continue:
-      nir_jump(&b->nb, nir_jump_continue);
-      break;
-   case vtn_branch_type_return:
-      nir_jump(&b->nb, nir_jump_return);
-      break;
-   default:
-      unreachable("Invalid branch type");
-   }
-}
-
-static void
-vtn_emit_cf_list(struct vtn_builder *b, struct list_head *cf_list,
-                 nir_variable *switch_fall_var, bool *has_switch_break)
-{
-   list_for_each_entry(struct vtn_cf_node, node, cf_list, link) {
-      switch (node->type) {
-      case vtn_cf_node_type_block: {
-         struct vtn_block *block = (struct vtn_block *)node;
-
-         block->block = nir_cursor_current_block(b->nb.cursor);
-         _mesa_hash_table_insert(b->block_table, block->block, block);
-
-         vtn_foreach_instruction(b, block->label,
-                                 block->merge ? block->merge : block->branch,
-                                 vtn_handle_body_instruction);
-
-         if ((*block->branch & SpvOpCodeMask) == SpvOpReturnValue) {
-            struct vtn_ssa_value *src = vtn_ssa_value(b, block->branch[1]);
-            vtn_variable_store(b, src,
-                               nir_deref_var_create(b, b->impl->return_var),
-                               NULL);
-         }
-
-         if (block->branch_type != vtn_branch_type_none) {
-            vtn_emit_branch(b, block->branch_type,
-                            switch_fall_var, has_switch_break);
-         }
-
-         break;
-      }
-
-      case vtn_cf_node_type_if: {
-         struct vtn_if *vtn_if = (struct vtn_if *)node;
-
-         nir_if *if_stmt = nir_if_create(b->shader);
-         if_stmt->condition =
-            nir_src_for_ssa(vtn_ssa_value(b, vtn_if->condition)->def);
-         nir_cf_node_insert(b->nb.cursor, &if_stmt->cf_node);
-
-         bool sw_break = false;
-
-         b->nb.cursor = nir_after_cf_list(&if_stmt->then_list);
-         if (vtn_if->then_type == vtn_branch_type_none)
-            vtn_emit_cf_list(b, &vtn_if->then_body, switch_fall_var, &sw_break);
-         else
-            vtn_emit_branch(b, vtn_if->then_type, switch_fall_var, &sw_break);
-
-         b->nb.cursor = nir_after_cf_list(&if_stmt->else_list);
-         if (vtn_if->else_type == vtn_branch_type_none)
-            vtn_emit_cf_list(b, &vtn_if->else_body, switch_fall_var, &sw_break);
-         else
-            vtn_emit_branch(b, vtn_if->else_type, switch_fall_var, &sw_break);
-
-         b->nb.cursor = nir_after_cf_node(&if_stmt->cf_node);
-
-         /* If we encountered a switch break somewhere inside of the if,
-          * then it would have been handled correctly by calling
-          * emit_cf_list or emit_branch for the interrior.  However, we
-          * need to predicate everything following on wether or not we're
-          * still going.
-          */
-         if (sw_break) {
-            *has_switch_break = true;
-
-            nir_if *switch_if = nir_if_create(b->shader);
-            switch_if->condition =
-               nir_src_for_ssa(nir_load_var(&b->nb, switch_fall_var));
-            nir_cf_node_insert(b->nb.cursor, &switch_if->cf_node);
-
-            b->nb.cursor = nir_after_cf_list(&if_stmt->then_list);
-         }
-         break;
-      }
-
-      case vtn_cf_node_type_loop: {
-         struct vtn_loop *vtn_loop = (struct vtn_loop *)node;
-
-         nir_loop *loop = nir_loop_create(b->shader);
-         nir_cf_node_insert(b->nb.cursor, &loop->cf_node);
-
-         if (!list_empty(&vtn_loop->cont_body)) {
-            /* If we have a non-trivial continue body then we need to put
-             * it at the beginning of the loop with a flag to ensure that
-             * it doesn't get executed in the first iteration.
-             */
-            nir_variable *do_cont =
-               nir_local_variable_create(b->nb.impl, glsl_bool_type(), "cont");
-
-            b->nb.cursor = nir_before_cf_node(&loop->cf_node);
-            nir_store_var(&b->nb, do_cont, nir_imm_int(&b->nb, NIR_FALSE), 1);
-
-            b->nb.cursor = nir_after_cf_list(&loop->body);
-            nir_if *cont_if = nir_if_create(b->shader);
-            cont_if->condition = nir_src_for_ssa(nir_load_var(&b->nb, do_cont));
-            nir_cf_node_insert(b->nb.cursor, &cont_if->cf_node);
-
-            b->nb.cursor = nir_after_cf_list(&cont_if->then_list);
-            vtn_emit_cf_list(b, &vtn_loop->cont_body, NULL, NULL);
-
-            b->nb.cursor = nir_after_cf_node(&cont_if->cf_node);
-            nir_store_var(&b->nb, do_cont, nir_imm_int(&b->nb, NIR_TRUE), 1);
-         }
-
-         b->nb.cursor = nir_after_cf_list(&loop->body);
-         vtn_emit_cf_list(b, &vtn_loop->body, NULL, NULL);
-
-         b->nb.cursor = nir_after_cf_node(&loop->cf_node);
-         break;
-      }
-
-      case vtn_cf_node_type_switch: {
-         struct vtn_switch *vtn_switch = (struct vtn_switch *)node;
-
-         /* First, we create a variable to keep track of whether or not the
-          * switch is still going at any given point.  Any switch breaks
-          * will set this variable to false.
-          */
-         nir_variable *fall_var =
-            nir_local_variable_create(b->nb.impl, glsl_bool_type(), "fall");
-         nir_store_var(&b->nb, fall_var, nir_imm_int(&b->nb, NIR_TRUE), 1);
-
-         /* Next, we gather up all of the conditions.  We have to do this
-          * up-front because we also need to build an "any" condition so
-          * that we can use !any for default.
-          */
-         const int num_cases = list_length(&vtn_switch->cases);
-         NIR_VLA(nir_ssa_def *, conditions, num_cases);
-
-         nir_ssa_def *sel = vtn_ssa_value(b, vtn_switch->selector)->def;
-         /* An accumulation of all conditions.  Used for the default */
-         nir_ssa_def *any = NULL;
-
-         int i = 0;
-         list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) {
-            if (cse->is_default) {
-               conditions[i++] = NULL;
-               continue;
-            }
-
-            nir_ssa_def *cond = NULL;
-            nir_array_foreach(&cse->values, uint32_t, val) {
-               nir_ssa_def *is_val =
-                  nir_ieq(&b->nb, sel, nir_imm_int(&b->nb, *val));
-
-               cond = cond ? nir_ior(&b->nb, cond, is_val) : is_val;
-            }
-
-            any = any ? nir_ior(&b->nb, any, cond) : cond;
-            conditions[i++] = cond;
-         }
-         assert(i == num_cases);
-
-         /* Now we can walk the list of cases and actually emit code */
-         i = 0;
-         list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) {
-            /* Figure out the condition */
-            nir_ssa_def *cond = conditions[i++];
-            if (cse->is_default) {
-               assert(cond == NULL);
-               cond = nir_inot(&b->nb, any);
-            }
-            /* Take fallthrough into account */
-            cond = nir_ior(&b->nb, cond, nir_load_var(&b->nb, fall_var));
-
-            nir_if *case_if = nir_if_create(b->nb.shader);
-            case_if->condition = nir_src_for_ssa(cond);
-            nir_cf_node_insert(b->nb.cursor, &case_if->cf_node);
-
-            bool has_break = false;
-            b->nb.cursor = nir_after_cf_list(&case_if->then_list);
-            vtn_emit_cf_list(b, &cse->body, fall_var, &has_break);
-            (void)has_break; /* We don't care */
-
-            b->nb.cursor = nir_after_cf_node(&case_if->cf_node);
-         }
-         assert(i == num_cases);
-
-         break;
-      }
-
-      default:
-         unreachable("Invalid CF node type");
-      }
-   }
-}
-
-
 nir_shader *
 spirv_to_nir(const uint32_t *words, size_t word_count,
              gl_shader_stage stage,
@@ -3839,9 +3619,7 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
                                                _mesa_key_pointer_equal);
       b->block_table = _mesa_hash_table_create(b, _mesa_hash_pointer,
                                                _mesa_key_pointer_equal);
-      nir_builder_init(&b->nb, b->impl);
-      b->nb.cursor = nir_after_cf_list(&b->impl->body);
-      vtn_emit_cf_list(b, &func->body, NULL, NULL);
+      vtn_function_emit(b, func, vtn_handle_body_instruction);
       vtn_foreach_instruction(b, func->start_block->label, func->end,
                               vtn_handle_phi_second_pass);
    }
index 9d8d451b5e0e0b70ec2fff58fa7fe17e5f447a06..7d25e96c8f0f101843a76fe5966484f05b84f756 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "vtn_private.h"
+#include "nir/nir_vla.h"
 
 static bool
 vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode,
@@ -448,3 +449,236 @@ vtn_build_cfg(struct vtn_builder *b, const uint32_t *words, const uint32_t *end)
                           NULL, NULL, NULL, NULL, NULL);
    }
 }
+
+/* XXX: This should go in nir_builder.h */
+static inline void
+nir_jump(nir_builder *build, nir_jump_type jump_type)
+{
+   nir_jump_instr *jump = nir_jump_instr_create(build->shader, jump_type);
+   nir_builder_instr_insert(build, &jump->instr);
+}
+
+static void
+vtn_emit_branch(struct vtn_builder *b, enum vtn_branch_type branch_type,
+                nir_variable *switch_fall_var, bool *has_switch_break)
+{
+   switch (branch_type) {
+   case vtn_branch_type_switch_break:
+      nir_store_var(&b->nb, switch_fall_var, nir_imm_int(&b->nb, NIR_FALSE), 1);
+      *has_switch_break = true;
+      break;
+   case vtn_branch_type_switch_fallthrough:
+      break; /* Nothing to do */
+   case vtn_branch_type_loop_break:
+      nir_jump(&b->nb, nir_jump_break);
+      break;
+   case vtn_branch_type_loop_continue:
+      nir_jump(&b->nb, nir_jump_continue);
+      break;
+   case vtn_branch_type_return:
+      nir_jump(&b->nb, nir_jump_return);
+      break;
+   default:
+      unreachable("Invalid branch type");
+   }
+}
+
+static void
+vtn_emit_cf_list(struct vtn_builder *b, struct list_head *cf_list,
+                 nir_variable *switch_fall_var, bool *has_switch_break,
+                 vtn_instruction_handler handler)
+{
+   list_for_each_entry(struct vtn_cf_node, node, cf_list, link) {
+      switch (node->type) {
+      case vtn_cf_node_type_block: {
+         struct vtn_block *block = (struct vtn_block *)node;
+
+         block->block = nir_cursor_current_block(b->nb.cursor);
+         _mesa_hash_table_insert(b->block_table, block->block, block);
+
+         vtn_foreach_instruction(b, block->label,
+                                 block->merge ? block->merge : block->branch,
+                                 handler);
+
+         if ((*block->branch & SpvOpCodeMask) == SpvOpReturnValue) {
+            struct vtn_ssa_value *src = vtn_ssa_value(b, block->branch[1]);
+            vtn_variable_store(b, src,
+                               nir_deref_var_create(b, b->impl->return_var),
+                               NULL);
+         }
+
+         if (block->branch_type != vtn_branch_type_none) {
+            vtn_emit_branch(b, block->branch_type,
+                            switch_fall_var, has_switch_break);
+         }
+
+         break;
+      }
+
+      case vtn_cf_node_type_if: {
+         struct vtn_if *vtn_if = (struct vtn_if *)node;
+
+         nir_if *if_stmt = nir_if_create(b->shader);
+         if_stmt->condition =
+            nir_src_for_ssa(vtn_ssa_value(b, vtn_if->condition)->def);
+         nir_cf_node_insert(b->nb.cursor, &if_stmt->cf_node);
+
+         bool sw_break = false;
+
+         b->nb.cursor = nir_after_cf_list(&if_stmt->then_list);
+         if (vtn_if->then_type == vtn_branch_type_none) {
+            vtn_emit_cf_list(b, &vtn_if->then_body,
+                             switch_fall_var, &sw_break, handler);
+         } else {
+            vtn_emit_branch(b, vtn_if->then_type, switch_fall_var, &sw_break);
+         }
+
+         b->nb.cursor = nir_after_cf_list(&if_stmt->else_list);
+         if (vtn_if->else_type == vtn_branch_type_none) {
+            vtn_emit_cf_list(b, &vtn_if->else_body,
+                             switch_fall_var, &sw_break, handler);
+         } else {
+            vtn_emit_branch(b, vtn_if->else_type, switch_fall_var, &sw_break);
+         }
+
+         b->nb.cursor = nir_after_cf_node(&if_stmt->cf_node);
+
+         /* If we encountered a switch break somewhere inside of the if,
+          * then it would have been handled correctly by calling
+          * emit_cf_list or emit_branch for the interrior.  However, we
+          * need to predicate everything following on wether or not we're
+          * still going.
+          */
+         if (sw_break) {
+            *has_switch_break = true;
+
+            nir_if *switch_if = nir_if_create(b->shader);
+            switch_if->condition =
+               nir_src_for_ssa(nir_load_var(&b->nb, switch_fall_var));
+            nir_cf_node_insert(b->nb.cursor, &switch_if->cf_node);
+
+            b->nb.cursor = nir_after_cf_list(&if_stmt->then_list);
+         }
+         break;
+      }
+
+      case vtn_cf_node_type_loop: {
+         struct vtn_loop *vtn_loop = (struct vtn_loop *)node;
+
+         nir_loop *loop = nir_loop_create(b->shader);
+         nir_cf_node_insert(b->nb.cursor, &loop->cf_node);
+
+         if (!list_empty(&vtn_loop->cont_body)) {
+            /* If we have a non-trivial continue body then we need to put
+             * it at the beginning of the loop with a flag to ensure that
+             * it doesn't get executed in the first iteration.
+             */
+            nir_variable *do_cont =
+               nir_local_variable_create(b->nb.impl, glsl_bool_type(), "cont");
+
+            b->nb.cursor = nir_before_cf_node(&loop->cf_node);
+            nir_store_var(&b->nb, do_cont, nir_imm_int(&b->nb, NIR_FALSE), 1);
+
+            b->nb.cursor = nir_after_cf_list(&loop->body);
+            nir_if *cont_if = nir_if_create(b->shader);
+            cont_if->condition = nir_src_for_ssa(nir_load_var(&b->nb, do_cont));
+            nir_cf_node_insert(b->nb.cursor, &cont_if->cf_node);
+
+            b->nb.cursor = nir_after_cf_list(&cont_if->then_list);
+            vtn_emit_cf_list(b, &vtn_loop->cont_body, NULL, NULL, handler);
+
+            b->nb.cursor = nir_after_cf_node(&cont_if->cf_node);
+            nir_store_var(&b->nb, do_cont, nir_imm_int(&b->nb, NIR_TRUE), 1);
+         }
+
+         b->nb.cursor = nir_after_cf_list(&loop->body);
+         vtn_emit_cf_list(b, &vtn_loop->body, NULL, NULL, handler);
+
+         b->nb.cursor = nir_after_cf_node(&loop->cf_node);
+         break;
+      }
+
+      case vtn_cf_node_type_switch: {
+         struct vtn_switch *vtn_switch = (struct vtn_switch *)node;
+
+         /* First, we create a variable to keep track of whether or not the
+          * switch is still going at any given point.  Any switch breaks
+          * will set this variable to false.
+          */
+         nir_variable *fall_var =
+            nir_local_variable_create(b->nb.impl, glsl_bool_type(), "fall");
+         nir_store_var(&b->nb, fall_var, nir_imm_int(&b->nb, NIR_TRUE), 1);
+
+         /* Next, we gather up all of the conditions.  We have to do this
+          * up-front because we also need to build an "any" condition so
+          * that we can use !any for default.
+          */
+         const int num_cases = list_length(&vtn_switch->cases);
+         NIR_VLA(nir_ssa_def *, conditions, num_cases);
+
+         nir_ssa_def *sel = vtn_ssa_value(b, vtn_switch->selector)->def;
+         /* An accumulation of all conditions.  Used for the default */
+         nir_ssa_def *any = NULL;
+
+         int i = 0;
+         list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) {
+            if (cse->is_default) {
+               conditions[i++] = NULL;
+               continue;
+            }
+
+            nir_ssa_def *cond = NULL;
+            nir_array_foreach(&cse->values, uint32_t, val) {
+               nir_ssa_def *is_val =
+                  nir_ieq(&b->nb, sel, nir_imm_int(&b->nb, *val));
+
+               cond = cond ? nir_ior(&b->nb, cond, is_val) : is_val;
+            }
+
+            any = any ? nir_ior(&b->nb, any, cond) : cond;
+            conditions[i++] = cond;
+         }
+         assert(i == num_cases);
+
+         /* Now we can walk the list of cases and actually emit code */
+         i = 0;
+         list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) {
+            /* Figure out the condition */
+            nir_ssa_def *cond = conditions[i++];
+            if (cse->is_default) {
+               assert(cond == NULL);
+               cond = nir_inot(&b->nb, any);
+            }
+            /* Take fallthrough into account */
+            cond = nir_ior(&b->nb, cond, nir_load_var(&b->nb, fall_var));
+
+            nir_if *case_if = nir_if_create(b->nb.shader);
+            case_if->condition = nir_src_for_ssa(cond);
+            nir_cf_node_insert(b->nb.cursor, &case_if->cf_node);
+
+            bool has_break = false;
+            b->nb.cursor = nir_after_cf_list(&case_if->then_list);
+            vtn_emit_cf_list(b, &cse->body, fall_var, &has_break, handler);
+            (void)has_break; /* We don't care */
+
+            b->nb.cursor = nir_after_cf_node(&case_if->cf_node);
+         }
+         assert(i == num_cases);
+
+         break;
+      }
+
+      default:
+         unreachable("Invalid CF node type");
+      }
+   }
+}
+
+void
+vtn_function_emit(struct vtn_builder *b, struct vtn_function *func,
+                  vtn_instruction_handler instruction_handler)
+{
+   nir_builder_init(&b->nb, func->impl);
+   b->nb.cursor = nir_after_cf_list(&func->impl->body);
+   vtn_emit_cf_list(b, &func->body, NULL, NULL, instruction_handler);
+}
index 6dfd01d5c248bb27432f98636823532af00bd0be..7ed62ee712b0a06536256755142525c7b57002f8 100644 (file)
@@ -162,12 +162,14 @@ struct vtn_function {
    SpvFunctionControlMask control;
 };
 
-void vtn_build_cfg(struct vtn_builder *b, const uint32_t *words,
-                   const uint32_t *end);
-
 typedef bool (*vtn_instruction_handler)(struct vtn_builder *, uint32_t,
                                         const uint32_t *, unsigned);
 
+void vtn_build_cfg(struct vtn_builder *b, const uint32_t *words,
+                   const uint32_t *end);
+void vtn_function_emit(struct vtn_builder *b, struct vtn_function *func,
+                       vtn_instruction_handler instruction_handler);
+
 const uint32_t *
 vtn_foreach_instruction(struct vtn_builder *b, const uint32_t *start,
                         const uint32_t *end, vtn_instruction_handler handler);
@@ -342,6 +344,10 @@ vtn_value(struct vtn_builder *b, uint32_t value_id,
 
 struct vtn_ssa_value *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id);
 
+void vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src,
+                        nir_deref_var *dest, struct vtn_type *dest_type);
+
+
 typedef void (*vtn_decoration_foreach_cb)(struct vtn_builder *,
                                           struct vtn_value *,
                                           int member,