[prev in list] [next in list] [prev in thread] [next in thread] 

List:       mesa3d-dev
Subject:    Re: [Mesa-dev] [PATCH v2 6/9] nir: Add a large constants optimization pass
From:       Jason Ekstrand <jason () jlekstrand ! net>
Date:       2018-06-30 5:02:19
Message-ID: CAOFGe97yG-O4qXKcXcgaHOqAQS_AKLh_+ZfCzQU+A5jXKnVCrQ () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


On Fri, Jun 29, 2018 at 9:56 PM, Timothy Arceri <tarceri@itsqueeze.com>
wrote:

> On 30/06/18 10:13, Jason Ekstrand wrote:
>
>> This pass searches for reasonably large local variables which can be
>> statically proven to be constant and moves them into shader constant
>> data.  This is especially useful when large tables are baked into the
>> shader source code because they can be moved into a UBO by the driver to
>> reduce register pressure and make indirect access cheaper.
>>
>> v2 (Jason Ekstrand):
>>   - Use a size/align function to ensure we get the right alignments
>>   - Use the newly added deref offset helpers
>> ---
>>   src/compiler/Makefile.sources              |   1 +
>>   src/compiler/nir/meson.build               |   1 +
>>   src/compiler/nir/nir.h                     |   4 +
>>   src/compiler/nir/nir_opt_large_constants.c | 301 +++++++++++++++++++++
>>   4 files changed, 307 insertions(+)
>>   create mode 100644 src/compiler/nir/nir_opt_large_constants.c
>>
>> diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.source
>> s
>> index 0fcbc5c5c5b..9e3fbdc2612 100644
>> --- a/src/compiler/Makefile.sources
>> +++ b/src/compiler/Makefile.sources
>> @@ -276,6 +276,7 @@ NIR_FILES = \
>>         nir/nir_opt_if.c \
>>         nir/nir_opt_intrinsics.c \
>>         nir/nir_opt_loop_unroll.c \
>> +       nir/nir_opt_large_constants.c \
>>         nir/nir_opt_move_comparisons.c \
>>         nir/nir_opt_move_load_ubo.c \
>>         nir/nir_opt_peephole_select.c \
>> diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build
>> index eb7fb7b121e..28aa8de7014 100644
>> --- a/src/compiler/nir/meson.build
>> +++ b/src/compiler/nir/meson.build
>> @@ -160,6 +160,7 @@ files_libnir = files(
>>     'nir_opt_global_to_local.c',
>>     'nir_opt_if.c',
>>     'nir_opt_intrinsics.c',
>> +  'nir_opt_large_constants.c',
>>     'nir_opt_loop_unroll.c',
>>     'nir_opt_move_comparisons.c',
>>     'nir_opt_move_load_ubo.c',
>> diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
>> index cc5f88d6f54..92ab3a699cc 100644
>> --- a/src/compiler/nir/nir.h
>> +++ b/src/compiler/nir/nir.h
>> @@ -2905,6 +2905,10 @@ bool nir_opt_if(nir_shader *shader);
>>     bool nir_opt_intrinsics(nir_shader *shader);
>>   +bool nir_opt_large_constants(nir_shader *shader,
>> +                             glsl_type_size_align_func size_align,
>> +                             unsigned threshold);
>> +
>>   bool nir_opt_loop_unroll(nir_shader *shader, nir_variable_mode
>> indirect_mask);
>>     bool nir_opt_move_comparisons(nir_shader *shader);
>> diff --git a/src/compiler/nir/nir_opt_large_constants.c
>> b/src/compiler/nir/nir_opt_large_constants.c
>> new file mode 100644
>> index 00000000000..027c6e8e5b5
>> --- /dev/null
>> +++ b/src/compiler/nir/nir_opt_large_constants.c
>> @@ -0,0 +1,301 @@
>> +/*
>> + * Copyright  © 2018 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining
>> a
>> + * copy of this software and associated documentation files (the
>> "Software"),
>> + * to deal in the Software without restriction, including without
>> limitation
>> + * the rights to use, copy, modify, merge, publish, distribute,
>> sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the
>> next
>> + * paragraph) shall be included in all copies or substantial portions of
>> the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>> SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> DEALINGS
>> + * IN THE SOFTWARE.
>> + */
>> +
>> +#include "nir.h"
>> +#include "nir_builder.h"
>> +#include "nir_deref.h"
>> +
>> +struct var_info {
>> +   bool is_constant;
>> +   bool found_read;
>> +};
>> +
>> +static nir_ssa_def *
>> +build_constant_load(nir_builder *b, nir_deref_instr *deref,
>> +                    glsl_type_size_align_func size_align)
>> +{
>> +   nir_variable *var = nir_deref_instr_get_variable(deref);
>> +
>> +   const unsigned bit_size = glsl_get_bit_size(deref->type);
>> +   const unsigned num_components = glsl_get_vector_elements(deref
>> ->type);
>> +
>> +   UNUSED unsigned var_size, var_align;
>> +   size_align(var->type, &var_size, &var_align);
>> +   assert(var->data.location % var_align == 0);
>> +
>> +   nir_intrinsic_instr *load =
>> +      nir_intrinsic_instr_create(b->shader,
>> nir_intrinsic_load_constant);
>> +   load->num_components = num_components;
>> +   nir_intrinsic_set_base(load, var->data.location);
>> +   nir_intrinsic_set_range(load, var_size);
>> +   load->src[0] = nir_src_for_ssa(nir_build_deref_offset(b, deref,
>> size_align));
>> +   nir_ssa_dest_init(&load->instr, &load->dest,
>> +                     num_components, bit_size, NULL);
>> +   nir_builder_instr_insert(b, &load->instr);
>> +
>> +   return &load->dest.ssa;
>> +}
>> +
>> +static void
>> +handle_constant_store(nir_builder *b, nir_intrinsic_instr *store,
>> +                      glsl_type_size_align_func size_align)
>> +{
>> +   nir_deref_instr *deref = nir_src_as_deref(store->src[0]);
>> +   assert(!nir_deref_instr_has_indirect(deref));
>> +
>> +   nir_variable *var = nir_deref_instr_get_variable(deref);
>> +
>> +   const unsigned bit_size = glsl_get_bit_size(deref->type);
>> +   const unsigned num_components = glsl_get_vector_elements(deref
>> ->type);
>> +
>> +   char *dst = (char *)b->shader->constant_data +
>> +               var->data.location +
>> +               nir_deref_instr_get_const_offset(deref, size_align);
>> +
>> +   nir_const_value *val = nir_src_as_const_value(store->src[1]);
>> +   switch (bit_size) {
>> +   case 8:
>> +      for (unsigned i = 0; i < num_components; i++)
>> +         ((uint8_t *)dst)[i] = val->u8[i];
>> +      break;
>> +
>> +   case 16:
>> +      for (unsigned i = 0; i < num_components; i++)
>> +         ((uint16_t *)dst)[i] = val->u16[i];
>> +      break;
>> +
>> +   case 32:
>> +      for (unsigned i = 0; i < num_components; i++)
>> +         ((uint32_t *)dst)[i] = val->u32[i];
>> +      break;
>> +
>> +   case 64:
>> +      for (unsigned i = 0; i < num_components; i++)
>> +         ((uint64_t *)dst)[i] = val->u64[i];
>> +      break;
>> +
>> +   default:
>> +      unreachable("Invalid bit size");
>> +   }
>> +}
>> +
>> +/** Lower large constant variables to shader constant data
>> + *
>> + * This pass looks for large (type_size(var->type) > threshold) variables
>> + * which are statically constant and moves them into shader constant
>> data.
>> + * This is especially useful when large tables are baked into the shader
>> + * source code because they can be moved into a UBO by the driver to
>> reduce
>> + * register pressure and make indirect access cheaper.
>> + */
>> +bool
>> +nir_opt_large_constants(nir_shader *shader,
>> +                        glsl_type_size_align_func size_align,
>> +                        unsigned threshold)
>> +{
>> +   /* Default to a natural alignment if none is provided */
>> +   if (size_align == NULL)
>> +      size_align = glsl_get_natural_size_align_bytes;
>> +
>> +   /* This only works with a single entrypoint */
>> +   nir_function_impl *impl = nir_shader_get_entrypoint(shader);
>> +
>> +   /* This pass can only be run once */
>> +   assert(shader->constant_data == NULL && shader->constant_data_size ==
>> 0);
>> +
>> +   /* The index parameter is unused for local variables so we'll use it
>> for
>> +    * indexing into our array of variable metadata.
>> +    */
>> +   unsigned num_locals = 0;
>> +   nir_foreach_variable(var, &impl->locals)
>> +      var->data.index = num_locals++;
>> +
>> +   struct var_info *var_infos = malloc(num_locals * sizeof(struct
>> var_info));
>> +   for (unsigned i = 0; i < num_locals; i++) {
>> +      var_infos[i] = (struct var_info) {
>> +         .is_constant = true,
>> +         .found_read = false,
>> +      };
>> +   }
>> +
>> +   /* First, walk through the shader and figure out what variables we can
>> +    * lower to the constant blob.
>> +    */
>> +   bool first_block = true;
>> +   nir_foreach_block(block, impl) {
>> +      nir_foreach_instr(instr, block) {
>> +         if (instr->type != nir_instr_type_intrinsic)
>> +            continue;
>> +
>> +         nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
>> +
>> +         bool src_is_const = false;
>> +         nir_deref_instr *src_deref = NULL, *dst_deref = NULL;
>> +         switch (intrin->intrinsic) {
>> +         case nir_intrinsic_store_deref:
>> +            dst_deref = nir_src_as_deref(intrin->src[0]);
>> +            src_is_const = nir_src_as_const_value(intrin->src[1]);
>> +            break;
>> +
>> +         case nir_intrinsic_load_deref:
>> +            src_deref = nir_src_as_deref(intrin->src[0]);
>> +            break;
>> +
>> +         case nir_intrinsic_copy_deref:
>>
>
> Can we add a comment here? Something like:
>
> /* We always assume the src and therefore the dst are not constants
>  * here. Copy and constant propagation passes should have taken
>  * care of this in most cases anyway.
>  */
>
> Does that sound correct?
>

Sounds fine with me.


> Otherwise this series is:
>
> Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
>

Thanks!

--Jason


> Although I don't know the code i patch 8 very well so maybe someone else
> might want to take a look over that.
>
>
> +            dst_deref = nir_src_as_deref(intrin->src[0]);
>> +            src_deref = nir_src_as_deref(intrin->src[1]);
>> +            src_is_const = false > +            break;
>> +
>> +         default:
>> +            continue;
>> +         }
>> +
>> +         if (dst_deref && dst_deref->mode == nir_var_local) {
>> +            nir_variable *var = nir_deref_instr_get_variable(dst_deref);
>> +            assert(var->data.mode == nir_var_local);
>> +
>> +            /* We only consider variables constant if they only have
>> constant
>> +             * stores, all the stores come before any reads, and all
>> stores
>> +             * come in the first block.  We also can't handle indirect
>> stores.
>> +             */
>> +            struct var_info *info = &var_infos[var->data.index];
>> +            if (!src_is_const || info->found_read || !first_block ||
>> +                nir_deref_instr_has_indirect(dst_deref))
>> +               info->is_constant = false;
>> +         }
>> +
>> +         if (src_deref && src_deref->mode == nir_var_local) {
>> +            nir_variable *var = nir_deref_instr_get_variable(src_deref);
>> +            assert(var->data.mode == nir_var_local);
>> +
>> +            var_infos[var->data.index].found_read = true;
>> +         }
>> +      }
>> +      first_block = false;
>> +   }
>> +
>> +   shader->constant_data_size = 0;
>> +   nir_foreach_variable(var, &impl->locals) {
>> +      struct var_info *info = &var_infos[var->data.index];
>> +      if (!info->is_constant)
>> +         continue;
>> +
>> +      unsigned var_size, var_align;
>> +      size_align(var->type, &var_size, &var_align);
>> +      if (var_size <= threshold || !info->found_read) {
>> +         /* Don't bother lowering small stuff or data that's never read
>> */
>> +         info->is_constant = false;
>> +         continue;
>> +      }
>> +
>> +      var->data.location = ALIGN_POT(shader->constant_data_size,
>> var_align);
>> +      shader->constant_data_size = var->data.location + var_size;
>> +   }
>> +
>> +   if (shader->constant_data_size == 0) {
>> +      free(var_infos);
>> +      return false;
>> +   }
>> +
>> +   shader->constant_data = rzalloc_size(shader,
>> shader->constant_data_size);
>> +
>> +   nir_builder b;
>> +   nir_builder_init(&b, impl);
>> +
>> +   nir_foreach_block(block, impl) {
>> +      nir_foreach_instr_safe(instr, block) {
>> +         if (instr->type != nir_instr_type_intrinsic)
>> +            continue;
>> +
>> +         nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
>> +
>> +         switch (intrin->intrinsic) {
>> +         case nir_intrinsic_load_deref: {
>> +            nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
>> +            if (deref->mode != nir_var_local)
>> +               continue;
>> +
>> +            nir_variable *var = nir_deref_instr_get_variable(deref);
>> +            struct var_info *info = &var_infos[var->data.index];
>> +            if (info->is_constant) {
>> +               b.cursor = nir_after_instr(&intrin->instr);
>> +               nir_ssa_def *val = build_constant_load(&b, deref,
>> size_align);
>> +               nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
>> +                                        nir_src_for_ssa(val));
>> +               nir_instr_remove(&intrin->instr);
>> +               nir_deref_instr_remove_if_unused(deref);
>> +            }
>> +            break;
>> +         }
>> +
>> +         case nir_intrinsic_store_deref: {
>> +            nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
>> +            if (deref->mode != nir_var_local)
>> +               continue;
>> +
>> +            nir_variable *var = nir_deref_instr_get_variable(deref);
>> +            struct var_info *info = &var_infos[var->data.index];
>> +            if (info->is_constant) {
>> +               b.cursor = nir_after_instr(&intrin->instr);
>> +               handle_constant_store(&b, intrin, size_align);
>> +               nir_instr_remove(&intrin->instr);
>> +               nir_deref_instr_remove_if_unused(deref);
>> +            }
>> +            break;
>> +         }
>> +
>> +         case nir_intrinsic_copy_deref: {
>> +            nir_deref_instr *deref = nir_src_as_deref(intrin->src[1]);
>> +            if (deref->mode != nir_var_local)
>> +               continue;
>> +
>> +            nir_variable *var = nir_deref_instr_get_variable(deref);
>> +            struct var_info *info = &var_infos[var->data.index];
>> +            if (info->is_constant) {
>> +               b.cursor = nir_after_instr(&intrin->instr);
>> +               nir_ssa_def *val = build_constant_load(&b, deref,
>> size_align);
>> +               nir_store_deref(&b, nir_src_as_deref(intrin->src[0]),
>> val, ~0);
>> +               nir_instr_remove(&intrin->instr);
>> +               nir_deref_instr_remove_if_unused(deref);
>> +            }
>> +            break;
>> +         }
>> +
>> +         default:
>> +            continue;
>> +         }
>> +      }
>> +   }
>> +
>> +   /* Clean up the now unused variables */
>> +   nir_foreach_variable_safe(var, &impl->locals) {
>> +      if (var_infos[var->data.index].is_constant)
>> +         exec_node_remove(&var->node);
>> +   }
>> +
>> +   free(var_infos);
>> +
>> +   nir_metadata_preserve(impl, nir_metadata_block_index |
>> +                               nir_metadata_dominance);
>> +   return true;
>> +}
>>
>>

[Attachment #5 (text/html)]

<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Jun 29, 2018 \
at 9:56 PM, Timothy Arceri <span dir="ltr">&lt;<a href="mailto:tarceri@itsqueeze.com" \
target="_blank">tarceri@itsqueeze.com</a>&gt;</span> wrote:<br><blockquote \
class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc \
solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On 30/06/18 10:13, Jason \
Ekstrand wrote:<br> <blockquote class="gmail_quote" style="margin:0 0 0 \
.8ex;border-left:1px #ccc solid;padding-left:1ex"> This pass searches for reasonably \
large local variables which can be<br> statically proven to be constant and moves \
them into shader constant<br> data.   This is especially useful when large tables are \
baked into the<br> shader source code because they can be moved into a UBO by the \
driver to<br> reduce register pressure and make indirect access cheaper.<br>
<br>
v2 (Jason Ekstrand):<br>
   - Use a size/align function to ensure we get the right alignments<br>
   - Use the newly added deref offset helpers<br>
---<br>
   src/compiler/Makefile.sources                     |     1 +<br>
   src/compiler/nir/meson.build                       |     1 +<br>
   src/compiler/nir/nir.h                                |     4 +<br>
   src/compiler/nir/nir_opt_large<wbr>_constants.c | 301 +++++++++++++++++++++<br>
   4 files changed, 307 insertions(+)<br>
   create mode 100644 src/compiler/nir/nir_opt_large<wbr>_constants.c<br>
<br>
diff --git a/src/compiler/Makefile.source<wbr>s \
b/src/compiler/Makefile.source<wbr>s<br> index 0fcbc5c5c5b..9e3fbdc2612 100644<br>
--- a/src/compiler/Makefile.source<wbr>s<br>
+++ b/src/compiler/Makefile.source<wbr>s<br>
@@ -276,6 +276,7 @@ NIR_FILES = \<br>
            nir/nir_opt_if.c \<br>
            nir/nir_opt_intrinsics.c \<br>
            nir/nir_opt_loop_unroll.c \<br>
+           nir/nir_opt_large_constants.c \<br>
            nir/nir_opt_move_comparisons.c \<br>
            nir/nir_opt_move_load_ubo.c \<br>
            nir/nir_opt_peephole_select.c \<br>
diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build<br>
index eb7fb7b121e..28aa8de7014 100644<br>
--- a/src/compiler/nir/meson.build<br>
+++ b/src/compiler/nir/meson.build<br>
@@ -160,6 +160,7 @@ files_libnir = files(<br>
      &#39;nir_opt_global_to_local.c&#39;,<br>
      &#39;nir_opt_if.c&#39;,<br>
      &#39;nir_opt_intrinsics.c&#39;,<br>
+   &#39;nir_opt_large_constants.c&#39;,<br>
      &#39;nir_opt_loop_unroll.c&#39;,<br>
      &#39;nir_opt_move_comparisons.c&#39;,<br>
      &#39;nir_opt_move_load_ubo.c&#39;,<br>
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h<br>
index cc5f88d6f54..92ab3a699cc 100644<br>
--- a/src/compiler/nir/nir.h<br>
+++ b/src/compiler/nir/nir.h<br>
@@ -2905,6 +2905,10 @@ bool nir_opt_if(nir_shader *shader);<br>
      bool nir_opt_intrinsics(nir_shader *shader);<br>
   +bool nir_opt_large_constants(nir_sh<wbr>ader *shader,<br>
+                                            glsl_type_size_align_func \
size_align,<br> +                                            unsigned threshold);<br>
+<br>
   bool nir_opt_loop_unroll(nir_shader *shader, nir_variable_mode indirect_mask);<br>
      bool nir_opt_move_comparisons(nir_s<wbr>hader *shader);<br>
diff --git a/src/compiler/nir/nir_opt_lar<wbr>ge_constants.c \
b/src/compiler/nir/nir_opt_lar<wbr>ge_constants.c<br> new file mode 100644<br>
index 00000000000..027c6e8e5b5<br>
--- /dev/null<br>
+++ b/src/compiler/nir/nir_opt_lar<wbr>ge_constants.c<br>
@@ -0,0 +1,301 @@<br>
+/*<br>
+ * Copyright  © 2018 Intel Corporation<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the \
&quot;Software&quot;),<br> + * to deal in the Software without restriction, including \
without limitation<br> + * the rights to use, copy, modify, merge, publish, \
distribute, sublicense,<br> + * and/or sell copies of the Software, and to permit \
persons to whom the<br> + * Software is furnished to do so, subject to the following \
conditions:<br> + *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS \
OR<br> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF \
MERCHANTABILITY,<br> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   IN \
NO EVENT SHALL<br> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \
DAMAGES OR OTHER<br> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR \
OTHERWISE, ARISING<br> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE \
OR OTHER DEALINGS<br> + * IN THE SOFTWARE.<br>
+ */<br>
+<br>
+#include &quot;nir.h&quot;<br>
+#include &quot;nir_builder.h&quot;<br>
+#include &quot;nir_deref.h&quot;<br>
+<br>
+struct var_info {<br>
+     bool is_constant;<br>
+     bool found_read;<br>
+};<br>
+<br>
+static nir_ssa_def *<br>
+build_constant_load(nir_build<wbr>er *b, nir_deref_instr *deref,<br>
+                              glsl_type_size_align_func size_align)<br>
+{<br>
+     nir_variable *var = nir_deref_instr_get_variable(d<wbr>eref);<br>
+<br>
+     const unsigned bit_size = glsl_get_bit_size(deref-&gt;type)<wbr>;<br>
+     const unsigned num_components = \
glsl_get_vector_elements(deref<wbr>-&gt;type);<br> +<br>
+     UNUSED unsigned var_size, var_align;<br>
+     size_align(var-&gt;type, &amp;var_size, &amp;var_align);<br>
+     assert(var-&gt;data.location % var_align == 0);<br>
+<br>
+     nir_intrinsic_instr *load =<br>
+         nir_intrinsic_instr_create(b-&gt;<wbr>shader, \
nir_intrinsic_load_constant);<br> +     load-&gt;num_components = num_components;<br>
+     nir_intrinsic_set_base(load, var-&gt;data.location);<br>
+     nir_intrinsic_set_range(load, var_size);<br>
+     load-&gt;src[0] = nir_src_for_ssa(nir_build_dere<wbr>f_offset(b, deref, \
size_align));<br> +     nir_ssa_dest_init(&amp;load-&gt;inst<wbr>r, \
&amp;load-&gt;dest,<br> +                                num_components, bit_size, \
NULL);<br> +     nir_builder_instr_insert(b, &amp;load-&gt;instr);<br>
+<br>
+     return &amp;load-&gt;dest.ssa;<br>
+}<br>
+<br>
+static void<br>
+handle_constant_store(nir_bui<wbr>lder *b, nir_intrinsic_instr *store,<br>
+                                 glsl_type_size_align_func size_align)<br>
+{<br>
+     nir_deref_instr *deref = nir_src_as_deref(store-&gt;src[0]<wbr>);<br>
+     assert(!nir_deref_instr_has_i<wbr>ndirect(deref));<br>
+<br>
+     nir_variable *var = nir_deref_instr_get_variable(d<wbr>eref);<br>
+<br>
+     const unsigned bit_size = glsl_get_bit_size(deref-&gt;type)<wbr>;<br>
+     const unsigned num_components = \
glsl_get_vector_elements(deref<wbr>-&gt;type);<br> +<br>
+     char *dst = (char *)b-&gt;shader-&gt;constant_data +<br>
+                       var-&gt;data.location +<br>
+                       nir_deref_instr_get_const_off<wbr>set(deref, size_align);<br>
+<br>
+     nir_const_value *val = nir_src_as_const_value(store-&gt;<wbr>src[1]);<br>
+     switch (bit_size) {<br>
+     case 8:<br>
+         for (unsigned i = 0; i &lt; num_components; i++)<br>
+              ((uint8_t *)dst)[i] = val-&gt;u8[i];<br>
+         break;<br>
+<br>
+     case 16:<br>
+         for (unsigned i = 0; i &lt; num_components; i++)<br>
+              ((uint16_t *)dst)[i] = val-&gt;u16[i];<br>
+         break;<br>
+<br>
+     case 32:<br>
+         for (unsigned i = 0; i &lt; num_components; i++)<br>
+              ((uint32_t *)dst)[i] = val-&gt;u32[i];<br>
+         break;<br>
+<br>
+     case 64:<br>
+         for (unsigned i = 0; i &lt; num_components; i++)<br>
+              ((uint64_t *)dst)[i] = val-&gt;u64[i];<br>
+         break;<br>
+<br>
+     default:<br>
+         unreachable(&quot;Invalid bit size&quot;);<br>
+     }<br>
+}<br>
+<br>
+/** Lower large constant variables to shader constant data<br>
+ *<br>
+ * This pass looks for large (type_size(var-&gt;type) &gt; threshold) variables<br>
+ * which are statically constant and moves them into shader constant data.<br>
+ * This is especially useful when large tables are baked into the shader<br>
+ * source code because they can be moved into a UBO by the driver to reduce<br>
+ * register pressure and make indirect access cheaper.<br>
+ */<br>
+bool<br>
+nir_opt_large_constants(nir_s<wbr>hader *shader,<br>
+                                    glsl_type_size_align_func size_align,<br>
+                                    unsigned threshold)<br>
+{<br>
+     /* Default to a natural alignment if none is provided */<br>
+     if (size_align == NULL)<br>
+         size_align = glsl_get_natural_size_align_by<wbr>tes;<br>
+<br>
+     /* This only works with a single entrypoint */<br>
+     nir_function_impl *impl = nir_shader_get_entrypoint(shad<wbr>er);<br>
+<br>
+     /* This pass can only be run once */<br>
+     assert(shader-&gt;constant_data == NULL &amp;&amp; \
shader-&gt;constant_data_size == 0);<br> +<br>
+     /* The index parameter is unused for local variables so we&#39;ll use it \
for<br> +      * indexing into our array of variable metadata.<br>
+      */<br>
+     unsigned num_locals = 0;<br>
+     nir_foreach_variable(var, &amp;impl-&gt;locals)<br>
+         var-&gt;data.index = num_locals++;<br>
+<br>
+     struct var_info *var_infos = malloc(num_locals * sizeof(struct var_info));<br>
+     for (unsigned i = 0; i &lt; num_locals; i++) {<br>
+         var_infos[i] = (struct var_info) {<br>
+              .is_constant = true,<br>
+              .found_read = false,<br>
+         };<br>
+     }<br>
+<br>
+     /* First, walk through the shader and figure out what variables we can<br>
+      * lower to the constant blob.<br>
+      */<br>
+     bool first_block = true;<br>
+     nir_foreach_block(block, impl) {<br>
+         nir_foreach_instr(instr, block) {<br>
+              if (instr-&gt;type != nir_instr_type_intrinsic)<br>
+                  continue;<br>
+<br>
+              nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);<br>
+<br>
+              bool src_is_const = false;<br>
+              nir_deref_instr *src_deref = NULL, *dst_deref = NULL;<br>
+              switch (intrin-&gt;intrinsic) {<br>
+              case nir_intrinsic_store_deref:<br>
+                  dst_deref = nir_src_as_deref(intrin-&gt;src[0<wbr>]);<br>
+                  src_is_const = nir_src_as_const_value(intrin-<wbr>&gt;src[1]);<br>
+                  break;<br>
+<br>
+              case nir_intrinsic_load_deref:<br>
+                  src_deref = nir_src_as_deref(intrin-&gt;src[0<wbr>]);<br>
+                  break;<br>
+<br>
+              case nir_intrinsic_copy_deref:<br>
</blockquote>
<br></div></div>
Can we add a comment here? Something like:<br>
<br>
/* We always assume the src and therefore the dst are not constants<br>
  * here. Copy and constant propagation passes should have taken<br>
  * care of this in most cases anyway.<br>
  */<br>
<br>
Does that sound correct?<br></blockquote><div><br></div><div>Sounds fine with \
me.<br></div><div>  </div><blockquote class="gmail_quote" style="margin:0 0 0 \
.8ex;border-left:1px #ccc solid;padding-left:1ex"> Otherwise this series is:<br>
<br>
Reviewed-by: Timothy Arceri &lt;<a href="mailto:tarceri@itsqueeze.com" \
target="_blank">tarceri@itsqueeze.com</a>&gt;<br></blockquote><div><br></div><div>Thanks!</div><div><br></div><div>--Jason<br></div><div> \
</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc \
solid;padding-left:1ex"> Although I don&#39;t know the code i patch 8 very well so \
maybe someone else might want to take a look over that.<div class="HOEnZb"><div \
class="h5"><br> <br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc \
solid;padding-left:1ex"> +                  dst_deref = \
nir_src_as_deref(intrin-&gt;src[0<wbr>]);<br> +                  src_deref = \
nir_src_as_deref(intrin-&gt;src[1<wbr>]);<br> +                  src_is_const = false \
&gt; +                  break;<br> +<br>
+              default:<br>
+                  continue;<br>
+              }<br>
+<br>
+              if (dst_deref &amp;&amp; dst_deref-&gt;mode == nir_var_local) {<br>
+                  nir_variable *var = \
nir_deref_instr_get_variable(d<wbr>st_deref);<br> +                  \
assert(var-&gt;data.mode == nir_var_local);<br> +<br>
+                  /* We only consider variables constant if they only have \
constant<br> +                    * stores, all the stores come before any reads, and \
all stores<br> +                    * come in the first block.   We also can&#39;t \
handle indirect stores.<br> +                    */<br>
+                  struct var_info *info = &amp;var_infos[var-&gt;data.index];<br>
+                  if (!src_is_const || info-&gt;found_read || !first_block ||<br>
+                        nir_deref_instr_has_indirect(d<wbr>st_deref))<br>
+                       info-&gt;is_constant = false;<br>
+              }<br>
+<br>
+              if (src_deref &amp;&amp; src_deref-&gt;mode == nir_var_local) {<br>
+                  nir_variable *var = \
nir_deref_instr_get_variable(s<wbr>rc_deref);<br> +                  \
assert(var-&gt;data.mode == nir_var_local);<br> +<br>
+                  var_infos[var-&gt;data.index].fou<wbr>nd_read = true;<br>
+              }<br>
+         }<br>
+         first_block = false;<br>
+     }<br>
+<br>
+     shader-&gt;constant_data_size = 0;<br>
+     nir_foreach_variable(var, &amp;impl-&gt;locals) {<br>
+         struct var_info *info = &amp;var_infos[var-&gt;data.index];<br>
+         if (!info-&gt;is_constant)<br>
+              continue;<br>
+<br>
+         unsigned var_size, var_align;<br>
+         size_align(var-&gt;type, &amp;var_size, &amp;var_align);<br>
+         if (var_size &lt;= threshold || !info-&gt;found_read) {<br>
+              /* Don&#39;t bother lowering small stuff or data that&#39;s never read \
*/<br> +              info-&gt;is_constant = false;<br>
+              continue;<br>
+         }<br>
+<br>
+         var-&gt;data.location = ALIGN_POT(shader-&gt;constant_dat<wbr>a_size, \
var_align);<br> +         shader-&gt;constant_data_size = var-&gt;data.location + \
var_size;<br> +     }<br>
+<br>
+     if (shader-&gt;constant_data_size == 0) {<br>
+         free(var_infos);<br>
+         return false;<br>
+     }<br>
+<br>
+     shader-&gt;constant_data = rzalloc_size(shader, \
shader-&gt;constant_data_size);<br> +<br>
+     nir_builder b;<br>
+     nir_builder_init(&amp;b, impl);<br>
+<br>
+     nir_foreach_block(block, impl) {<br>
+         nir_foreach_instr_safe(instr, block) {<br>
+              if (instr-&gt;type != nir_instr_type_intrinsic)<br>
+                  continue;<br>
+<br>
+              nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);<br>
+<br>
+              switch (intrin-&gt;intrinsic) {<br>
+              case nir_intrinsic_load_deref: {<br>
+                  nir_deref_instr *deref = \
nir_src_as_deref(intrin-&gt;src[0<wbr>]);<br> +                  if (deref-&gt;mode \
!= nir_var_local)<br> +                       continue;<br>
+<br>
+                  nir_variable *var = nir_deref_instr_get_variable(d<wbr>eref);<br>
+                  struct var_info *info = &amp;var_infos[var-&gt;data.index];<br>
+                  if (info-&gt;is_constant) {<br>
+                       b.cursor = nir_after_instr(&amp;intrin-&gt;instr<wbr>);<br>
+                       nir_ssa_def *val = build_constant_load(&amp;b, deref, \
size_align);<br> +                       \
nir_ssa_def_rewrite_uses(&amp;int<wbr>rin-&gt;dest.ssa,<br> +                         \
nir_src_for_ssa(val));<br> +                       \
nir_instr_remove(&amp;intrin-&gt;ins<wbr>tr);<br> +                       \
nir_deref_instr_remove_if_unu<wbr>sed(deref);<br> +                  }<br>
+                  break;<br>
+              }<br>
+<br>
+              case nir_intrinsic_store_deref: {<br>
+                  nir_deref_instr *deref = \
nir_src_as_deref(intrin-&gt;src[0<wbr>]);<br> +                  if (deref-&gt;mode \
!= nir_var_local)<br> +                       continue;<br>
+<br>
+                  nir_variable *var = nir_deref_instr_get_variable(d<wbr>eref);<br>
+                  struct var_info *info = &amp;var_infos[var-&gt;data.index];<br>
+                  if (info-&gt;is_constant) {<br>
+                       b.cursor = nir_after_instr(&amp;intrin-&gt;instr<wbr>);<br>
+                       handle_constant_store(&amp;b, intrin, size_align);<br>
+                       nir_instr_remove(&amp;intrin-&gt;ins<wbr>tr);<br>
+                       nir_deref_instr_remove_if_unu<wbr>sed(deref);<br>
+                  }<br>
+                  break;<br>
+              }<br>
+<br>
+              case nir_intrinsic_copy_deref: {<br>
+                  nir_deref_instr *deref = \
nir_src_as_deref(intrin-&gt;src[1<wbr>]);<br> +                  if (deref-&gt;mode \
!= nir_var_local)<br> +                       continue;<br>
+<br>
+                  nir_variable *var = nir_deref_instr_get_variable(d<wbr>eref);<br>
+                  struct var_info *info = &amp;var_infos[var-&gt;data.index];<br>
+                  if (info-&gt;is_constant) {<br>
+                       b.cursor = nir_after_instr(&amp;intrin-&gt;instr<wbr>);<br>
+                       nir_ssa_def *val = build_constant_load(&amp;b, deref, \
size_align);<br> +                       nir_store_deref(&amp;b, \
nir_src_as_deref(intrin-&gt;src[0<wbr>]), val, ~0);<br> +                       \
nir_instr_remove(&amp;intrin-&gt;ins<wbr>tr);<br> +                       \
nir_deref_instr_remove_if_unu<wbr>sed(deref);<br> +                  }<br>
+                  break;<br>
+              }<br>
+<br>
+              default:<br>
+                  continue;<br>
+              }<br>
+         }<br>
+     }<br>
+<br>
+     /* Clean up the now unused variables */<br>
+     nir_foreach_variable_safe(<wbr>var, &amp;impl-&gt;locals) {<br>
+         if (var_infos[var-&gt;data.index].is<wbr>_constant)<br>
+              exec_node_remove(&amp;var-&gt;node);<br>
+     }<br>
+<br>
+     free(var_infos);<br>
+<br>
+     nir_metadata_preserve(impl, nir_metadata_block_index |<br>
+                                               nir_metadata_dominance);<br>
+     return true;<br>
+}<br>
<br>
</blockquote>
</div></div></blockquote></div><br></div></div>


[Attachment #6 (text/plain)]

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic