Home | History | Annotate | Download | only in nir
      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  *    Connor Abbott (cwabbott0 (at) gmail.com)
     25  *
     26  */
     27 
     28 #include "nir.h"
     29 #include "nir_builder.h"
     30 #include "nir_phi_builder.h"
     31 #include "nir_vla.h"
     32 
     33 struct regs_to_ssa_state {
     34    nir_shader *shader;
     35 
     36    struct nir_phi_builder_value **values;
     37 };
     38 
     39 static bool
     40 rewrite_src(nir_src *src, void *_state)
     41 {
     42    struct regs_to_ssa_state *state = _state;
     43 
     44    if (src->is_ssa)
     45       return true;
     46 
     47    nir_instr *instr = src->parent_instr;
     48    nir_register *reg = src->reg.reg;
     49    struct nir_phi_builder_value *value = state->values[reg->index];
     50    if (!value)
     51       return true;
     52 
     53    nir_block *block;
     54    if (instr->type == nir_instr_type_phi) {
     55       nir_phi_src *phi_src = exec_node_data(nir_phi_src, src, src);
     56       block = phi_src->pred;
     57    } else {
     58       block = instr->block;
     59    }
     60 
     61    nir_ssa_def *def = nir_phi_builder_value_get_block_def(value, block);
     62    nir_instr_rewrite_src(instr, src, nir_src_for_ssa(def));
     63 
     64    return true;
     65 }
     66 
     67 static void
     68 rewrite_if_condition(nir_if *nif, struct regs_to_ssa_state *state)
     69 {
     70    if (nif->condition.is_ssa)
     71       return;
     72 
     73    nir_block *block = nir_cf_node_as_block(nir_cf_node_prev(&nif->cf_node));
     74    nir_register *reg = nif->condition.reg.reg;
     75    struct nir_phi_builder_value *value = state->values[reg->index];
     76    if (!value)
     77       return;
     78 
     79    nir_ssa_def *def = nir_phi_builder_value_get_block_def(value, block);
     80    nir_if_rewrite_condition(nif, nir_src_for_ssa(def));
     81 }
     82 
     83 static bool
     84 rewrite_dest(nir_dest *dest, void *_state)
     85 {
     86    struct regs_to_ssa_state *state = _state;
     87 
     88    if (dest->is_ssa)
     89       return true;
     90 
     91    nir_instr *instr = dest->reg.parent_instr;
     92    nir_register *reg = dest->reg.reg;
     93    struct nir_phi_builder_value *value = state->values[reg->index];
     94    if (!value)
     95       return true;
     96 
     97    list_del(&dest->reg.def_link);
     98    nir_ssa_dest_init(instr, dest, reg->num_components,
     99                      reg->bit_size, reg->name);
    100 
    101    nir_phi_builder_value_set_block_def(value, instr->block, &dest->ssa);
    102 
    103    return true;
    104 }
    105 
    106 static void
    107 rewrite_alu_instr(nir_alu_instr *alu, struct regs_to_ssa_state *state)
    108 {
    109    nir_foreach_src(&alu->instr, rewrite_src, state);
    110 
    111    if (alu->dest.dest.is_ssa)
    112       return;
    113 
    114    nir_register *reg = alu->dest.dest.reg.reg;
    115    struct nir_phi_builder_value *value = state->values[reg->index];
    116    if (!value)
    117       return;
    118 
    119    unsigned write_mask = alu->dest.write_mask;
    120    if (write_mask == (1 << reg->num_components) - 1) {
    121       /* This is the simple case where the instruction writes all the
    122        * components.  We can handle that the same as any other destination.
    123        */
    124       rewrite_dest(&alu->dest.dest, state);
    125       return;
    126    }
    127 
    128    /* Calculate the number of components the final instruction, which for
    129     * per-component things is the number of output components of the
    130     * instruction and non-per-component things is the number of enabled
    131     * channels in the write mask.
    132     */
    133    unsigned num_components;
    134    unsigned vec_swizzle[4] = { 0, 1, 2, 3 };
    135    if (nir_op_infos[alu->op].output_size == 0) {
    136       /* Figure out the swizzle we need on the vecN operation and compute
    137        * the number of components in the SSA def at the same time.
    138        */
    139       num_components = 0;
    140       for (unsigned index = 0; index < 4; index++) {
    141          if (write_mask & (1 << index))
    142             vec_swizzle[index] = num_components++;
    143       }
    144 
    145       /* When we change the output writemask, we need to change
    146        * the swizzles for per-component inputs too
    147        */
    148       for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) {
    149          if (nir_op_infos[alu->op].input_sizes[i] != 0)
    150             continue;
    151 
    152          /*
    153           * We keep two indices:
    154           * 1. The index of the original (non-SSA) component
    155           * 2. The index of the post-SSA, compacted, component
    156           *
    157           * We need to map the swizzle component at index 1 to the swizzle
    158           * component at index 2.  Since index 1 is always larger than
    159           * index 2, we can do it in a single loop.
    160           */
    161 
    162          unsigned ssa_index = 0;
    163          for (unsigned index = 0; index < 4; index++) {
    164             if (!((write_mask >> index) & 1))
    165                continue;
    166 
    167             alu->src[i].swizzle[ssa_index++] = alu->src[i].swizzle[index];
    168          }
    169          assert(ssa_index == num_components);
    170       }
    171    } else {
    172       num_components = nir_op_infos[alu->op].output_size;
    173    }
    174    assert(num_components <= 4);
    175 
    176    alu->dest.write_mask = (1 << num_components) - 1;
    177    list_del(&alu->dest.dest.reg.def_link);
    178    nir_ssa_dest_init(&alu->instr, &alu->dest.dest, num_components,
    179                      reg->bit_size, reg->name);
    180 
    181    nir_op vecN_op;
    182    switch (reg->num_components) {
    183    case 2: vecN_op = nir_op_vec2; break;
    184    case 3: vecN_op = nir_op_vec3; break;
    185    case 4: vecN_op = nir_op_vec4; break;
    186    default: unreachable("not reached");
    187    }
    188 
    189    nir_alu_instr *vec = nir_alu_instr_create(state->shader, vecN_op);
    190 
    191    nir_ssa_def *old_src =
    192       nir_phi_builder_value_get_block_def(value, alu->instr.block);
    193    nir_ssa_def *new_src = &alu->dest.dest.ssa;
    194 
    195    for (unsigned i = 0; i < reg->num_components; i++) {
    196       if (write_mask & (1 << i)) {
    197          vec->src[i].src = nir_src_for_ssa(new_src);
    198          vec->src[i].swizzle[0] = vec_swizzle[i];
    199       } else {
    200          vec->src[i].src = nir_src_for_ssa(old_src);
    201          vec->src[i].swizzle[0] = i;
    202       }
    203    }
    204 
    205    nir_ssa_dest_init(&vec->instr, &vec->dest.dest, reg->num_components,
    206                      reg->bit_size, reg->name);
    207    nir_instr_insert(nir_after_instr(&alu->instr), &vec->instr);
    208 
    209    nir_phi_builder_value_set_block_def(value, alu->instr.block,
    210                                        &vec->dest.dest.ssa);
    211 }
    212 
    213 void
    214 nir_lower_regs_to_ssa_impl(nir_function_impl *impl)
    215 {
    216    if (exec_list_is_empty(&impl->registers))
    217       return;
    218 
    219    nir_metadata_require(impl, nir_metadata_block_index |
    220                               nir_metadata_dominance);
    221    nir_index_local_regs(impl);
    222 
    223    struct regs_to_ssa_state state;
    224    state.shader = impl->function->shader;
    225    state.values = malloc(impl->reg_alloc * sizeof(*state.values));
    226 
    227    struct nir_phi_builder *phi_build = nir_phi_builder_create(impl);
    228 
    229    const unsigned block_set_words = BITSET_WORDS(impl->num_blocks);
    230    NIR_VLA(BITSET_WORD, defs, block_set_words);
    231 
    232    nir_foreach_register(reg, &impl->registers) {
    233       if (reg->num_array_elems != 0 || reg->is_packed) {
    234          /* This pass only really works on "plain" registers.  If it's a
    235           * packed or array register, just set the value to NULL so that the
    236           * rewrite portion of the pass will know to ignore it.
    237           */
    238          state.values[reg->index] = NULL;
    239          continue;
    240       }
    241 
    242       memset(defs, 0, block_set_words * sizeof(*defs));
    243 
    244       nir_foreach_def(dest, reg)
    245          BITSET_SET(defs, dest->reg.parent_instr->block->index);
    246 
    247       state.values[reg->index] =
    248          nir_phi_builder_add_value(phi_build, reg->num_components,
    249                                    reg->bit_size, defs);
    250    }
    251 
    252    nir_foreach_block(block, impl) {
    253       nir_foreach_instr(instr, block) {
    254          if (instr->type == nir_instr_type_alu) {
    255             rewrite_alu_instr(nir_instr_as_alu(instr), &state);
    256          } else {
    257             nir_foreach_src(instr, rewrite_src, &state);
    258             nir_foreach_dest(instr, rewrite_dest, &state);
    259          }
    260       }
    261 
    262       nir_if *following_if = nir_block_get_following_if(block);
    263       if (following_if)
    264          rewrite_if_condition(following_if, &state);
    265    }
    266 
    267    nir_phi_builder_finish(phi_build);
    268 
    269    nir_foreach_register_safe(reg, &impl->registers) {
    270       if (state.values[reg->index]) {
    271          assert(list_empty(&reg->uses));
    272          assert(list_empty(&reg->if_uses));
    273          assert(list_empty(&reg->defs));
    274          exec_node_remove(&reg->node);
    275       }
    276    }
    277 
    278    free(state.values);
    279 
    280    nir_metadata_preserve(impl, nir_metadata_block_index |
    281                                nir_metadata_dominance);
    282 }
    283 
    284 void
    285 nir_lower_regs_to_ssa(nir_shader *shader)
    286 {
    287    assert(exec_list_is_empty(&shader->registers));
    288 
    289    nir_foreach_function(function, shader) {
    290       if (function->impl)
    291          nir_lower_regs_to_ssa_impl(function->impl);
    292    }
    293 }
    294