"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/compiler/nir/nir_lower_io_to_scalar.c" (16 Sep 2020, 14100 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "nir_lower_io_to_scalar.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright © 2016 Broadcom
    3  *
    4  * Permission is hereby granted, free of charge, to any person obtaining a
    5  * copy of this software and associated documentation files (the "Software"),
    6  * to deal in the Software without restriction, including without limitation
    7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    8  * and/or sell copies of the Software, and to permit persons to whom the
    9  * Software is furnished to do so, subject to the following conditions:
   10  *
   11  * The above copyright notice and this permission notice (including the next
   12  * paragraph) shall be included in all copies or substantial portions of the
   13  * Software.
   14  *
   15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   21  * IN THE SOFTWARE.
   22  */
   23 
   24 #include "nir.h"
   25 #include "nir_builder.h"
   26 #include "nir_deref.h"
   27 
   28 /** @file nir_lower_io_to_scalar.c
   29  *
   30  * Replaces nir_load_input/nir_store_output operations with num_components !=
   31  * 1 with individual per-channel operations.
   32  */
   33 
   34 static void
   35 lower_load_input_to_scalar(nir_builder *b, nir_intrinsic_instr *intr)
   36 {
   37    b->cursor = nir_before_instr(&intr->instr);
   38 
   39    assert(intr->dest.is_ssa);
   40 
   41    nir_ssa_def *loads[NIR_MAX_VEC_COMPONENTS];
   42 
   43    for (unsigned i = 0; i < intr->num_components; i++) {
   44       nir_intrinsic_instr *chan_intr =
   45          nir_intrinsic_instr_create(b->shader, intr->intrinsic);
   46       nir_ssa_dest_init(&chan_intr->instr, &chan_intr->dest,
   47                         1, intr->dest.ssa.bit_size, NULL);
   48       chan_intr->num_components = 1;
   49 
   50       nir_intrinsic_set_base(chan_intr, nir_intrinsic_base(intr));
   51       nir_intrinsic_set_component(chan_intr, nir_intrinsic_component(intr) + i);
   52       nir_intrinsic_set_type(chan_intr, nir_intrinsic_type(intr));
   53       /* offset */
   54       nir_src_copy(&chan_intr->src[0], &intr->src[0], chan_intr);
   55 
   56       nir_builder_instr_insert(b, &chan_intr->instr);
   57 
   58       loads[i] = &chan_intr->dest.ssa;
   59    }
   60 
   61    nir_ssa_def_rewrite_uses(&intr->dest.ssa,
   62                             nir_src_for_ssa(nir_vec(b, loads,
   63                                                     intr->num_components)));
   64    nir_instr_remove(&intr->instr);
   65 }
   66 
   67 static void
   68 lower_store_output_to_scalar(nir_builder *b, nir_intrinsic_instr *intr)
   69 {
   70    b->cursor = nir_before_instr(&intr->instr);
   71 
   72    nir_ssa_def *value = nir_ssa_for_src(b, intr->src[0], intr->num_components);
   73 
   74    for (unsigned i = 0; i < intr->num_components; i++) {
   75       if (!(nir_intrinsic_write_mask(intr) & (1 << i)))
   76          continue;
   77 
   78       nir_intrinsic_instr *chan_intr =
   79          nir_intrinsic_instr_create(b->shader, intr->intrinsic);
   80       chan_intr->num_components = 1;
   81 
   82       nir_intrinsic_set_base(chan_intr, nir_intrinsic_base(intr));
   83       nir_intrinsic_set_write_mask(chan_intr, 0x1);
   84       nir_intrinsic_set_component(chan_intr, nir_intrinsic_component(intr) + i);
   85       nir_intrinsic_set_type(chan_intr, nir_intrinsic_type(intr));
   86 
   87       /* value */
   88       chan_intr->src[0] = nir_src_for_ssa(nir_channel(b, value, i));
   89       /* offset */
   90       nir_src_copy(&chan_intr->src[1], &intr->src[1], chan_intr);
   91 
   92       nir_builder_instr_insert(b, &chan_intr->instr);
   93    }
   94 
   95    nir_instr_remove(&intr->instr);
   96 }
   97 
   98 void
   99 nir_lower_io_to_scalar(nir_shader *shader, nir_variable_mode mask)
  100 {
  101    nir_foreach_function(function, shader) {
  102       if (function->impl) {
  103          nir_builder b;
  104          nir_builder_init(&b, function->impl);
  105 
  106          nir_foreach_block(block, function->impl) {
  107             nir_foreach_instr_safe(instr, block) {
  108                if (instr->type != nir_instr_type_intrinsic)
  109                   continue;
  110 
  111                nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
  112 
  113                if (intr->num_components == 1)
  114                   continue;
  115 
  116                switch (intr->intrinsic) {
  117                case nir_intrinsic_load_input:
  118                   if (mask & nir_var_shader_in)
  119                      lower_load_input_to_scalar(&b, intr);
  120                   break;
  121                case nir_intrinsic_store_output:
  122                   if (mask & nir_var_shader_out)
  123                      lower_store_output_to_scalar(&b, intr);
  124                   break;
  125                default:
  126                   break;
  127                }
  128             }
  129          }
  130       }
  131    }
  132 }
  133 
  134 static nir_variable **
  135 get_channel_variables(struct hash_table *ht, nir_variable *var)
  136 {
  137    nir_variable **chan_vars;
  138    struct hash_entry *entry = _mesa_hash_table_search(ht, var);
  139    if (!entry) {
  140       chan_vars = (nir_variable **) calloc(4, sizeof(nir_variable *));
  141       _mesa_hash_table_insert(ht, var, chan_vars);
  142    } else {
  143       chan_vars = (nir_variable **) entry->data;
  144    }
  145 
  146    return chan_vars;
  147 }
  148 
  149 /*
  150  * Note that the src deref that we are cloning is the head of the
  151  * chain of deref instructions from the original intrinsic, but
  152  * the dst we are cloning to is the tail (because chains of deref
  153  * instructions are created back to front)
  154  */
  155 
  156 static nir_deref_instr *
  157 clone_deref_array(nir_builder *b, nir_deref_instr *dst_tail,
  158                   const nir_deref_instr *src_head)
  159 {
  160    const nir_deref_instr *parent = nir_deref_instr_parent(src_head);
  161 
  162    if (!parent)
  163       return dst_tail;
  164 
  165    assert(src_head->deref_type == nir_deref_type_array);
  166 
  167    dst_tail = clone_deref_array(b, dst_tail, parent);
  168 
  169    return nir_build_deref_array(b, dst_tail,
  170                                 nir_ssa_for_src(b, src_head->arr.index, 1));
  171 }
  172 
  173 static void
  174 lower_load_to_scalar_early(nir_builder *b, nir_intrinsic_instr *intr,
  175                            nir_variable *var, struct hash_table *split_inputs,
  176                            struct hash_table *split_outputs)
  177 {
  178    b->cursor = nir_before_instr(&intr->instr);
  179 
  180    assert(intr->dest.is_ssa);
  181 
  182    nir_ssa_def *loads[NIR_MAX_VEC_COMPONENTS];
  183 
  184    nir_variable **chan_vars;
  185    if (var->data.mode == nir_var_shader_in) {
  186       chan_vars = get_channel_variables(split_inputs, var);
  187    } else {
  188       chan_vars = get_channel_variables(split_outputs, var);
  189    }
  190 
  191    for (unsigned i = 0; i < intr->num_components; i++) {
  192       nir_variable *chan_var = chan_vars[var->data.location_frac + i];
  193       if (!chan_vars[var->data.location_frac + i]) {
  194          chan_var = nir_variable_clone(var, b->shader);
  195          chan_var->data.location_frac =  var->data.location_frac + i;
  196          chan_var->type = glsl_channel_type(chan_var->type);
  197          if (var->data.explicit_offset) {
  198             unsigned comp_size = glsl_get_bit_size(chan_var->type) / 8;
  199             chan_var->data.offset = var->data.offset + i * comp_size;
  200          }
  201 
  202          chan_vars[var->data.location_frac + i] = chan_var;
  203 
  204          nir_shader_add_variable(b->shader, chan_var);
  205       }
  206 
  207       nir_intrinsic_instr *chan_intr =
  208          nir_intrinsic_instr_create(b->shader, intr->intrinsic);
  209       nir_ssa_dest_init(&chan_intr->instr, &chan_intr->dest,
  210                         1, intr->dest.ssa.bit_size, NULL);
  211       chan_intr->num_components = 1;
  212 
  213       nir_deref_instr *deref = nir_build_deref_var(b, chan_var);
  214 
  215       deref = clone_deref_array(b, deref, nir_src_as_deref(intr->src[0]));
  216 
  217       chan_intr->src[0] = nir_src_for_ssa(&deref->dest.ssa);
  218 
  219       if (intr->intrinsic == nir_intrinsic_interp_deref_at_offset ||
  220           intr->intrinsic == nir_intrinsic_interp_deref_at_sample ||
  221           intr->intrinsic == nir_intrinsic_interp_deref_at_vertex)
  222          nir_src_copy(&chan_intr->src[1], &intr->src[1], &chan_intr->instr);
  223 
  224       nir_builder_instr_insert(b, &chan_intr->instr);
  225 
  226       loads[i] = &chan_intr->dest.ssa;
  227    }
  228 
  229    nir_ssa_def_rewrite_uses(&intr->dest.ssa,
  230                             nir_src_for_ssa(nir_vec(b, loads,
  231                                                     intr->num_components)));
  232 
  233    /* Remove the old load intrinsic */
  234    nir_instr_remove(&intr->instr);
  235 }
  236 
  237 static void
  238 lower_store_output_to_scalar_early(nir_builder *b, nir_intrinsic_instr *intr,
  239                                    nir_variable *var,
  240                                    struct hash_table *split_outputs)
  241 {
  242    b->cursor = nir_before_instr(&intr->instr);
  243 
  244    nir_ssa_def *value = nir_ssa_for_src(b, intr->src[1], intr->num_components);
  245 
  246    nir_variable **chan_vars = get_channel_variables(split_outputs, var);
  247    for (unsigned i = 0; i < intr->num_components; i++) {
  248       if (!(nir_intrinsic_write_mask(intr) & (1 << i)))
  249          continue;
  250 
  251       nir_variable *chan_var = chan_vars[var->data.location_frac + i];
  252       if (!chan_vars[var->data.location_frac + i]) {
  253          chan_var = nir_variable_clone(var, b->shader);
  254          chan_var->data.location_frac =  var->data.location_frac + i;
  255          chan_var->type = glsl_channel_type(chan_var->type);
  256          if (var->data.explicit_offset) {
  257             unsigned comp_size = glsl_get_bit_size(chan_var->type) / 8;
  258             chan_var->data.offset = var->data.offset + i * comp_size;
  259          }
  260 
  261          chan_vars[var->data.location_frac + i] = chan_var;
  262 
  263          nir_shader_add_variable(b->shader, chan_var);
  264       }
  265 
  266       nir_intrinsic_instr *chan_intr =
  267          nir_intrinsic_instr_create(b->shader, intr->intrinsic);
  268       chan_intr->num_components = 1;
  269 
  270       nir_intrinsic_set_write_mask(chan_intr, 0x1);
  271 
  272       nir_deref_instr *deref = nir_build_deref_var(b, chan_var);
  273 
  274       deref = clone_deref_array(b, deref, nir_src_as_deref(intr->src[0]));
  275 
  276       chan_intr->src[0] = nir_src_for_ssa(&deref->dest.ssa);
  277       chan_intr->src[1] = nir_src_for_ssa(nir_channel(b, value, i));
  278 
  279       nir_builder_instr_insert(b, &chan_intr->instr);
  280    }
  281 
  282    /* Remove the old store intrinsic */
  283    nir_instr_remove(&intr->instr);
  284 }
  285 
  286 /*
  287  * This function is intended to be called earlier than nir_lower_io_to_scalar()
  288  * i.e. before nir_lower_io() is called.
  289  */
  290 void
  291 nir_lower_io_to_scalar_early(nir_shader *shader, nir_variable_mode mask)
  292 {
  293    struct hash_table *split_inputs = _mesa_pointer_hash_table_create(NULL);
  294    struct hash_table *split_outputs = _mesa_pointer_hash_table_create(NULL);
  295 
  296    nir_foreach_function(function, shader) {
  297       if (function->impl) {
  298          nir_builder b;
  299          nir_builder_init(&b, function->impl);
  300 
  301          nir_foreach_block(block, function->impl) {
  302             nir_foreach_instr_safe(instr, block) {
  303                if (instr->type != nir_instr_type_intrinsic)
  304                   continue;
  305 
  306                nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
  307 
  308                if (intr->num_components == 1)
  309                   continue;
  310 
  311                if (intr->intrinsic != nir_intrinsic_load_deref &&
  312                    intr->intrinsic != nir_intrinsic_store_deref &&
  313                    intr->intrinsic != nir_intrinsic_interp_deref_at_centroid &&
  314                    intr->intrinsic != nir_intrinsic_interp_deref_at_sample &&
  315                    intr->intrinsic != nir_intrinsic_interp_deref_at_offset &&
  316                    intr->intrinsic != nir_intrinsic_interp_deref_at_vertex)
  317                   continue;
  318 
  319                nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
  320                nir_variable_mode mode = deref->mode;
  321                if (!(mode & mask))
  322                   continue;
  323 
  324                nir_variable *var = nir_deref_instr_get_variable(deref);
  325 
  326                /* TODO: add patch support */
  327                if (var->data.patch)
  328                   continue;
  329 
  330                /* TODO: add doubles support */
  331                if (glsl_type_is_64bit(glsl_without_array(var->type)))
  332                   continue;
  333 
  334                if (!(shader->info.stage == MESA_SHADER_VERTEX &&
  335                      mode == nir_var_shader_in) &&
  336                    var->data.location < VARYING_SLOT_VAR0 &&
  337                    var->data.location >= 0)
  338                   continue;
  339 
  340                /* Don't bother splitting if we can't opt away any unused
  341                 * components.
  342                 */
  343                if (var->data.always_active_io)
  344                   continue;
  345 
  346               /* Skip types we cannot split */
  347               if (glsl_type_is_matrix(glsl_without_array(var->type)) ||
  348                   glsl_type_is_struct_or_ifc(glsl_without_array(var->type)))
  349                  continue;
  350 
  351                switch (intr->intrinsic) {
  352                case nir_intrinsic_interp_deref_at_centroid:
  353                case nir_intrinsic_interp_deref_at_sample:
  354                case nir_intrinsic_interp_deref_at_offset:
  355                case nir_intrinsic_interp_deref_at_vertex:
  356                case nir_intrinsic_load_deref:
  357                   if ((mask & nir_var_shader_in && mode == nir_var_shader_in) ||
  358                       (mask & nir_var_shader_out && mode == nir_var_shader_out))
  359                      lower_load_to_scalar_early(&b, intr, var, split_inputs,
  360                                                 split_outputs);
  361                   break;
  362                case nir_intrinsic_store_deref:
  363                   if (mask & nir_var_shader_out &&
  364                       mode == nir_var_shader_out)
  365                      lower_store_output_to_scalar_early(&b, intr, var,
  366                                                         split_outputs);
  367                   break;
  368                default:
  369                   break;
  370                }
  371             }
  372          }
  373       }
  374    }
  375 
  376    /* Remove old input from the shaders inputs list */
  377    hash_table_foreach(split_inputs, entry) {
  378       nir_variable *var = (nir_variable *) entry->key;
  379       exec_node_remove(&var->node);
  380 
  381       free(entry->data);
  382    }
  383 
  384    /* Remove old output from the shaders outputs list */
  385    hash_table_foreach(split_outputs, entry) {
  386       nir_variable *var = (nir_variable *) entry->key;
  387       exec_node_remove(&var->node);
  388 
  389       free(entry->data);
  390    }
  391 
  392    _mesa_hash_table_destroy(split_inputs, NULL);
  393    _mesa_hash_table_destroy(split_outputs, NULL);
  394 
  395    nir_remove_dead_derefs(shader);
  396 }