"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/compiler/nir/nir_lower_locals_to_regs.c" (16 Sep 2020, 9144 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_locals_to_regs.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20.1.5_vs_20.2.0-rc1.

    1 /*
    2  * Copyright © 2014 Intel Corporation
    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  * Authors:
   24  *    Jason Ekstrand (jason@jlekstrand.net)
   25  *
   26  */
   27 
   28 #include "nir.h"
   29 #include "nir_builder.h"
   30 
   31 struct locals_to_regs_state {
   32    nir_builder builder;
   33 
   34    /* A hash table mapping derefs to registers */
   35    struct hash_table *regs_table;
   36 
   37    bool progress;
   38 };
   39 
   40 /* The following two functions implement a hash and equality check for
   41  * variable dreferences.  When the hash or equality function encounters an
   42  * array, it ignores the offset and whether it is direct or indirect
   43  * entirely.
   44  */
   45 static uint32_t
   46 hash_deref(const void *void_deref)
   47 {
   48    uint32_t hash = _mesa_fnv32_1a_offset_bias;
   49 
   50    for (const nir_deref_instr *deref = void_deref; deref;
   51         deref = nir_deref_instr_parent(deref)) {
   52       switch (deref->deref_type) {
   53       case nir_deref_type_var:
   54          return _mesa_fnv32_1a_accumulate(hash, deref->var);
   55 
   56       case nir_deref_type_array:
   57          continue; /* Do nothing */
   58 
   59       case nir_deref_type_struct:
   60          hash = _mesa_fnv32_1a_accumulate(hash, deref->strct.index);
   61          continue;
   62 
   63       default:
   64          unreachable("Invalid deref type");
   65       }
   66    }
   67 
   68    unreachable("We should have hit a variable dereference");
   69 }
   70 
   71 static bool
   72 derefs_equal(const void *void_a, const void *void_b)
   73 {
   74    for (const nir_deref_instr *a = void_a, *b = void_b; a || b;
   75         a = nir_deref_instr_parent(a), b = nir_deref_instr_parent(b)) {
   76       if (a->deref_type != b->deref_type)
   77          return false;
   78 
   79       switch (a->deref_type) {
   80       case nir_deref_type_var:
   81          return a->var == b->var;
   82 
   83       case nir_deref_type_array:
   84          continue; /* Do nothing */
   85 
   86       case nir_deref_type_struct:
   87          if (a->strct.index != b->strct.index)
   88             return false;
   89          continue;
   90 
   91       default:
   92          unreachable("Invalid deref type");
   93       }
   94    }
   95 
   96    unreachable("We should have hit a variable dereference");
   97 }
   98 
   99 static nir_register *
  100 get_reg_for_deref(nir_deref_instr *deref, struct locals_to_regs_state *state)
  101 {
  102    uint32_t hash = hash_deref(deref);
  103 
  104    assert(nir_deref_instr_get_variable(deref)->constant_initializer == NULL &&
  105           nir_deref_instr_get_variable(deref)->pointer_initializer == NULL);
  106 
  107    struct hash_entry *entry =
  108       _mesa_hash_table_search_pre_hashed(state->regs_table, hash, deref);
  109    if (entry)
  110       return entry->data;
  111 
  112    unsigned array_size = 1;
  113    for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
  114       if (d->deref_type == nir_deref_type_array)
  115          array_size *= glsl_get_length(nir_deref_instr_parent(d)->type);
  116    }
  117 
  118    assert(glsl_type_is_vector_or_scalar(deref->type));
  119 
  120    nir_register *reg = nir_local_reg_create(state->builder.impl);
  121    reg->num_components = glsl_get_vector_elements(deref->type);
  122    reg->num_array_elems = array_size > 1 ? array_size : 0;
  123    reg->bit_size = glsl_get_bit_size(deref->type);
  124 
  125    _mesa_hash_table_insert_pre_hashed(state->regs_table, hash, deref, reg);
  126 
  127    return reg;
  128 }
  129 
  130 static nir_src
  131 get_deref_reg_src(nir_deref_instr *deref, struct locals_to_regs_state *state)
  132 {
  133    nir_builder *b = &state->builder;
  134 
  135    nir_src src;
  136 
  137    src.is_ssa = false;
  138    src.reg.reg = get_reg_for_deref(deref, state);
  139    src.reg.base_offset = 0;
  140    src.reg.indirect = NULL;
  141 
  142    /* It is possible for a user to create a shader that has an array with a
  143     * single element and then proceed to access it indirectly.  Indirectly
  144     * accessing a non-array register is not allowed in NIR.  In order to
  145     * handle this case we just convert it to a direct reference.
  146     */
  147    if (src.reg.reg->num_array_elems == 0)
  148       return src;
  149 
  150    unsigned inner_array_size = 1;
  151    for (const nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
  152       if (d->deref_type != nir_deref_type_array)
  153          continue;
  154 
  155       if (nir_src_is_const(d->arr.index) && !src.reg.indirect) {
  156          src.reg.base_offset += nir_src_as_uint(d->arr.index) *
  157                                 inner_array_size;
  158       } else {
  159          if (src.reg.indirect) {
  160             assert(src.reg.base_offset == 0);
  161          } else {
  162             src.reg.indirect = ralloc(b->shader, nir_src);
  163             *src.reg.indirect =
  164                nir_src_for_ssa(nir_imm_int(b, src.reg.base_offset));
  165             src.reg.base_offset = 0;
  166          }
  167 
  168          assert(src.reg.indirect->is_ssa);
  169          nir_ssa_def *index = nir_i2i(b, nir_ssa_for_src(b, d->arr.index, 1), 32);
  170          src.reg.indirect->ssa =
  171             nir_iadd(b, src.reg.indirect->ssa,
  172                         nir_imul(b, index, nir_imm_int(b, inner_array_size)));
  173       }
  174 
  175       inner_array_size *= glsl_get_length(nir_deref_instr_parent(d)->type);
  176    }
  177 
  178    return src;
  179 }
  180 
  181 static bool
  182 lower_locals_to_regs_block(nir_block *block,
  183                            struct locals_to_regs_state *state)
  184 {
  185    nir_builder *b = &state->builder;
  186 
  187    nir_foreach_instr_safe(instr, block) {
  188       if (instr->type != nir_instr_type_intrinsic)
  189          continue;
  190 
  191       nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
  192 
  193       switch (intrin->intrinsic) {
  194       case nir_intrinsic_load_deref: {
  195          nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
  196          if (deref->mode != nir_var_function_temp)
  197             continue;
  198 
  199          b->cursor = nir_before_instr(&intrin->instr);
  200 
  201          nir_alu_instr *mov = nir_alu_instr_create(b->shader, nir_op_mov);
  202          mov->src[0].src = get_deref_reg_src(deref, state);
  203          mov->dest.write_mask = (1 << intrin->num_components) - 1;
  204          if (intrin->dest.is_ssa) {
  205             nir_ssa_dest_init(&mov->instr, &mov->dest.dest,
  206                               intrin->num_components,
  207                               intrin->dest.ssa.bit_size, NULL);
  208             nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
  209                                      nir_src_for_ssa(&mov->dest.dest.ssa));
  210          } else {
  211             nir_dest_copy(&mov->dest.dest, &intrin->dest, &mov->instr);
  212          }
  213          nir_builder_instr_insert(b, &mov->instr);
  214 
  215          nir_instr_remove(&intrin->instr);
  216          state->progress = true;
  217          break;
  218       }
  219 
  220       case nir_intrinsic_store_deref: {
  221          nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
  222          if (deref->mode != nir_var_function_temp)
  223             continue;
  224 
  225          b->cursor = nir_before_instr(&intrin->instr);
  226 
  227          nir_src reg_src = get_deref_reg_src(deref, state);
  228 
  229          nir_alu_instr *mov = nir_alu_instr_create(b->shader, nir_op_mov);
  230          nir_src_copy(&mov->src[0].src, &intrin->src[1], mov);
  231          mov->dest.write_mask = nir_intrinsic_write_mask(intrin);
  232          mov->dest.dest.is_ssa = false;
  233          mov->dest.dest.reg.reg = reg_src.reg.reg;
  234          mov->dest.dest.reg.base_offset = reg_src.reg.base_offset;
  235          mov->dest.dest.reg.indirect = reg_src.reg.indirect;
  236 
  237          nir_builder_instr_insert(b, &mov->instr);
  238 
  239          nir_instr_remove(&intrin->instr);
  240          state->progress = true;
  241          break;
  242       }
  243 
  244       case nir_intrinsic_copy_deref:
  245          unreachable("There should be no copies whatsoever at this point");
  246          break;
  247 
  248       default:
  249          continue;
  250       }
  251    }
  252 
  253    return true;
  254 }
  255 
  256 static bool
  257 nir_lower_locals_to_regs_impl(nir_function_impl *impl)
  258 {
  259    struct locals_to_regs_state state;
  260 
  261    nir_builder_init(&state.builder, impl);
  262    state.progress = false;
  263    state.regs_table = _mesa_hash_table_create(NULL, hash_deref, derefs_equal);
  264 
  265    nir_metadata_require(impl, nir_metadata_dominance);
  266 
  267    nir_foreach_block(block, impl) {
  268       lower_locals_to_regs_block(block, &state);
  269    }
  270 
  271    nir_metadata_preserve(impl, nir_metadata_block_index |
  272                                nir_metadata_dominance);
  273 
  274    _mesa_hash_table_destroy(state.regs_table, NULL);
  275 
  276    return state.progress;
  277 }
  278 
  279 bool
  280 nir_lower_locals_to_regs(nir_shader *shader)
  281 {
  282    bool progress = false;
  283 
  284    nir_foreach_function(function, shader) {
  285       if (function->impl)
  286          progress = nir_lower_locals_to_regs_impl(function->impl) || progress;
  287    }
  288 
  289    return progress;
  290 }