"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/compiler/nir/nir_opt_constant_folding.c" (16 Sep 2020, 8934 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_opt_constant_folding.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_constant_expressions.h"
   29 #include <math.h>
   30 
   31 /*
   32  * Implements SSA-based constant folding.
   33  */
   34 
   35 struct constant_fold_state {
   36    nir_shader *shader;
   37    unsigned execution_mode;
   38    bool has_load_constant;
   39    bool has_indirect_load_const;
   40 };
   41 
   42 static bool
   43 constant_fold_alu_instr(struct constant_fold_state *state, nir_alu_instr *instr)
   44 {
   45    nir_const_value src[NIR_MAX_VEC_COMPONENTS][NIR_MAX_VEC_COMPONENTS];
   46 
   47    if (!instr->dest.dest.is_ssa)
   48       return false;
   49 
   50    /* In the case that any outputs/inputs have unsized types, then we need to
   51     * guess the bit-size. In this case, the validator ensures that all
   52     * bit-sizes match so we can just take the bit-size from first
   53     * output/input with an unsized type. If all the outputs/inputs are sized
   54     * then we don't need to guess the bit-size at all because the code we
   55     * generate for constant opcodes in this case already knows the sizes of
   56     * the types involved and does not need the provided bit-size for anything
   57     * (although it still requires to receive a valid bit-size).
   58     */
   59    unsigned bit_size = 0;
   60    if (!nir_alu_type_get_type_size(nir_op_infos[instr->op].output_type))
   61       bit_size = instr->dest.dest.ssa.bit_size;
   62 
   63    for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) {
   64       if (!instr->src[i].src.is_ssa)
   65          return false;
   66 
   67       if (bit_size == 0 &&
   68           !nir_alu_type_get_type_size(nir_op_infos[instr->op].input_types[i]))
   69          bit_size = instr->src[i].src.ssa->bit_size;
   70 
   71       nir_instr *src_instr = instr->src[i].src.ssa->parent_instr;
   72 
   73       if (src_instr->type != nir_instr_type_load_const)
   74          return false;
   75       nir_load_const_instr* load_const = nir_instr_as_load_const(src_instr);
   76 
   77       for (unsigned j = 0; j < nir_ssa_alu_instr_src_components(instr, i);
   78            j++) {
   79          src[i][j] = load_const->value[instr->src[i].swizzle[j]];
   80       }
   81 
   82       /* We shouldn't have any source modifiers in the optimization loop. */
   83       assert(!instr->src[i].abs && !instr->src[i].negate);
   84    }
   85 
   86    if (bit_size == 0)
   87       bit_size = 32;
   88 
   89    /* We shouldn't have any saturate modifiers in the optimization loop. */
   90    assert(!instr->dest.saturate);
   91 
   92    nir_const_value dest[NIR_MAX_VEC_COMPONENTS];
   93    nir_const_value *srcs[NIR_MAX_VEC_COMPONENTS];
   94    memset(dest, 0, sizeof(dest));
   95    for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; ++i)
   96       srcs[i] = src[i];
   97    nir_eval_const_opcode(instr->op, dest, instr->dest.dest.ssa.num_components,
   98                          bit_size, srcs, state->execution_mode);
   99 
  100    nir_load_const_instr *new_instr =
  101       nir_load_const_instr_create(state->shader,
  102                                   instr->dest.dest.ssa.num_components,
  103                                   instr->dest.dest.ssa.bit_size);
  104 
  105    memcpy(new_instr->value, dest, sizeof(*new_instr->value) * new_instr->def.num_components);
  106 
  107    nir_instr_insert_before(&instr->instr, &new_instr->instr);
  108 
  109    nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa,
  110                             nir_src_for_ssa(&new_instr->def));
  111 
  112    nir_instr_remove(&instr->instr);
  113    ralloc_free(instr);
  114 
  115    return true;
  116 }
  117 
  118 static bool
  119 constant_fold_intrinsic_instr(struct constant_fold_state *state, nir_intrinsic_instr *instr)
  120 {
  121    bool progress = false;
  122 
  123    if ((instr->intrinsic == nir_intrinsic_demote_if ||
  124         instr->intrinsic == nir_intrinsic_discard_if) &&
  125        nir_src_is_const(instr->src[0])) {
  126       if (nir_src_as_bool(instr->src[0])) {
  127          nir_intrinsic_op op = instr->intrinsic == nir_intrinsic_discard_if ?
  128                                nir_intrinsic_discard :
  129                                nir_intrinsic_demote;
  130          nir_intrinsic_instr *new_instr = nir_intrinsic_instr_create(state->shader, op);
  131          nir_instr_insert_before(&instr->instr, &new_instr->instr);
  132          nir_instr_remove(&instr->instr);
  133          progress = true;
  134       } else {
  135          /* We're not discarding, just delete the instruction */
  136          nir_instr_remove(&instr->instr);
  137          progress = true;
  138       }
  139    } else if (instr->intrinsic == nir_intrinsic_load_constant) {
  140       state->has_load_constant = true;
  141 
  142       if (!nir_src_is_const(instr->src[0])) {
  143          state->has_indirect_load_const = true;
  144          return progress;
  145       }
  146 
  147       unsigned offset = nir_src_as_uint(instr->src[0]);
  148       unsigned base = nir_intrinsic_base(instr);
  149       unsigned range = nir_intrinsic_range(instr);
  150       assert(base + range <= state->shader->constant_data_size);
  151 
  152       nir_instr *new_instr = NULL;
  153       if (offset >= range) {
  154          nir_ssa_undef_instr *undef =
  155             nir_ssa_undef_instr_create(state->shader,
  156                                        instr->num_components,
  157                                        instr->dest.ssa.bit_size);
  158 
  159          nir_ssa_def_rewrite_uses(&instr->dest.ssa, nir_src_for_ssa(&undef->def));
  160          new_instr = &undef->instr;
  161       } else {
  162          nir_load_const_instr *load_const =
  163             nir_load_const_instr_create(state->shader,
  164                                         instr->num_components,
  165                                         instr->dest.ssa.bit_size);
  166 
  167          uint8_t *data = (uint8_t*)state->shader->constant_data + base;
  168          for (unsigned i = 0; i < instr->num_components; i++) {
  169             unsigned bytes = instr->dest.ssa.bit_size / 8;
  170             bytes = MIN2(bytes, range - offset);
  171 
  172             memcpy(&load_const->value[i].u64, data + offset, bytes);
  173             offset += bytes;
  174          }
  175 
  176          nir_ssa_def_rewrite_uses(&instr->dest.ssa, nir_src_for_ssa(&load_const->def));
  177          new_instr = &load_const->instr;
  178       }
  179 
  180       nir_instr_insert_before(&instr->instr, new_instr);
  181       nir_instr_remove(&instr->instr);
  182       progress = true;
  183    }
  184 
  185    return progress;
  186 }
  187 
  188 static bool
  189 constant_fold_block(struct constant_fold_state *state, nir_block *block)
  190 {
  191    bool progress = false;
  192 
  193    nir_foreach_instr_safe(instr, block) {
  194       switch (instr->type) {
  195       case nir_instr_type_alu:
  196          progress |= constant_fold_alu_instr(state, nir_instr_as_alu(instr));
  197          break;
  198       case nir_instr_type_intrinsic:
  199          progress |=
  200             constant_fold_intrinsic_instr(state, nir_instr_as_intrinsic(instr));
  201          break;
  202       default:
  203          /* Don't know how to constant fold */
  204          break;
  205       }
  206    }
  207 
  208    return progress;
  209 }
  210 
  211 static bool
  212 nir_opt_constant_folding_impl(struct constant_fold_state *state, nir_function_impl *impl)
  213 {
  214    bool progress = false;
  215 
  216    nir_foreach_block(block, impl) {
  217       progress |= constant_fold_block(state, block);
  218    }
  219 
  220    if (progress) {
  221       nir_metadata_preserve(impl, nir_metadata_block_index |
  222                                   nir_metadata_dominance);
  223    } else {
  224 #ifndef NDEBUG
  225       impl->valid_metadata &= ~nir_metadata_not_properly_reset;
  226 #endif
  227    }
  228 
  229    return progress;
  230 }
  231 
  232 bool
  233 nir_opt_constant_folding(nir_shader *shader)
  234 {
  235    bool progress = false;
  236    struct constant_fold_state state;
  237    state.shader = shader;
  238    state.execution_mode = shader->info.float_controls_execution_mode;
  239    state.has_load_constant = false;
  240    state.has_indirect_load_const = false;
  241 
  242    nir_foreach_function(function, shader) {
  243       if (function->impl)
  244          progress |= nir_opt_constant_folding_impl(&state, function->impl);
  245    }
  246 
  247    /* This doesn't free the constant data if there are no constant loads because
  248     * the data might still be used but the loads have been lowered to load_ubo
  249     */
  250    if (state.has_load_constant && !state.has_indirect_load_const &&
  251        shader->constant_data_size) {
  252       ralloc_free(shader->constant_data);
  253       shader->constant_data = NULL;
  254       shader->constant_data_size = 0;
  255    }
  256 
  257    return progress;
  258 }