spirv: Only emit functions which are actually used
authorJason Ekstrand <jason.ekstrand@intel.com>
Thu, 19 Oct 2017 17:11:22 +0000 (10:11 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Sat, 2 Dec 2017 16:07:35 +0000 (08:07 -0800)
Instead of emitting absolutely everything, just emit the few functions
that are actually referenced in some way by the entrypoint.  This should
save us quite a bit of time when handed large shader modules containing
many entrypoints.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Kristian H. Kristensen <hoegsberg@google.com>
src/compiler/spirv/spirv_to_nir.c
src/compiler/spirv/vtn_cfg.c
src/compiler/spirv/vtn_private.h

index c58cf5cbfdf84ccf9d45a5b4d058e63103b172d2..2c4f5b0c93e485b2363ed836b35e33a20c3bcb86 100644 (file)
@@ -1394,8 +1394,11 @@ vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode,
                          const uint32_t *w, unsigned count)
 {
    struct vtn_type *res_type = vtn_value(b, w[1], vtn_value_type_type)->type;
-   struct nir_function *callee =
-      vtn_value(b, w[3], vtn_value_type_function)->func->impl->function;
+   struct vtn_function *vtn_callee =
+      vtn_value(b, w[3], vtn_value_type_function)->func;
+   struct nir_function *callee = vtn_callee->impl->function;
+
+   vtn_callee->referenced = true;
 
    nir_call_instr *call = nir_call_instr_create(b->nb.shader, callee);
    for (unsigned i = 0; i < call->num_params; i++) {
@@ -3366,12 +3369,22 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
 
    vtn_build_cfg(b, words, word_end);
 
-   foreach_list_typed(struct vtn_function, func, node, &b->functions) {
-      b->const_table = _mesa_hash_table_create(b, _mesa_hash_pointer,
-                                               _mesa_key_pointer_equal);
-
-      vtn_function_emit(b, func, vtn_handle_body_instruction);
-   }
+   assert(b->entry_point->value_type == vtn_value_type_function);
+   b->entry_point->func->referenced = true;
+
+   bool progress;
+   do {
+      progress = false;
+      foreach_list_typed(struct vtn_function, func, node, &b->functions) {
+         if (func->referenced && !func->emitted) {
+            b->const_table = _mesa_hash_table_create(b, _mesa_hash_pointer,
+                                                     _mesa_key_pointer_equal);
+
+            vtn_function_emit(b, func, vtn_handle_body_instruction);
+            progress = true;
+         }
+      }
+   } while (progress);
 
    assert(b->entry_point->value_type == vtn_value_type_function);
    nir_function *entry_point = b->entry_point->func->impl->function;
index 13f022177100cc4e43c6f11c21054c75e04e01b1..70bbccb7cddd23e7e9ca694d7f2c44ef14fb30d5 100644 (file)
@@ -783,4 +783,6 @@ vtn_function_emit(struct vtn_builder *b, struct vtn_function *func,
     */
    if (b->has_loop_continue)
       nir_repair_ssa_impl(func->impl);
+
+   func->emitted = true;
 }
index 173a7b3d7c7f98180d059f96a117d0eed6f5c1c6..751f5011b7d48bf76214d96a4ed89d1379f4504e 100644 (file)
@@ -159,6 +159,9 @@ struct vtn_block {
 struct vtn_function {
    struct exec_node node;
 
+   bool referenced;
+   bool emitted;
+
    nir_function_impl *impl;
    struct vtn_block *start_block;