Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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@gmail.com)
  25.  *
  26.  */
  27.  
  28. #include "nir.h"
  29. #include <main/imports.h>
  30.  
  31. /**
  32.  * SSA-based copy propagation
  33.  */
  34.  
  35. static bool is_move(nir_alu_instr *instr)
  36. {
  37.    if (instr->op != nir_op_fmov &&
  38.        instr->op != nir_op_imov)
  39.       return false;
  40.  
  41.    if (instr->dest.saturate)
  42.       return false;
  43.  
  44.    /* we handle modifiers in a separate pass */
  45.  
  46.    if (instr->src[0].abs || instr->src[0].negate)
  47.       return false;
  48.  
  49.    if (!instr->src[0].src.is_ssa)
  50.       return false;
  51.  
  52.    return true;
  53.  
  54. }
  55.  
  56. static bool is_vec(nir_alu_instr *instr)
  57. {
  58.    for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++)
  59.       if (!instr->src[i].src.is_ssa)
  60.          return false;
  61.  
  62.    return instr->op == nir_op_vec2 ||
  63.           instr->op == nir_op_vec3 ||
  64.           instr->op == nir_op_vec4;
  65. }
  66.  
  67. static bool
  68. is_swizzleless_move(nir_alu_instr *instr)
  69. {
  70.    if (is_move(instr)) {
  71.       for (unsigned i = 0; i < 4; i++) {
  72.          if (!((instr->dest.write_mask >> i) & 1))
  73.             break;
  74.          if (instr->src[0].swizzle[i] != i)
  75.             return false;
  76.       }
  77.       return true;
  78.    } else if (is_vec(instr)) {
  79.       nir_ssa_def *def = NULL;
  80.       for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) {
  81.          if (instr->src[i].swizzle[0] != i)
  82.             return false;
  83.  
  84.          if (def == NULL) {
  85.             def = instr->src[i].src.ssa;
  86.          } else if (instr->src[i].src.ssa != def) {
  87.             return false;
  88.          }
  89.       }
  90.       return true;
  91.    } else {
  92.       return false;
  93.    }
  94. }
  95.  
  96. static bool
  97. copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if)
  98. {
  99.    if (!src->is_ssa) {
  100.       if (src->reg.indirect)
  101.          return copy_prop_src(src, parent_instr, parent_if);
  102.       return false;
  103.    }
  104.  
  105.    nir_instr *src_instr = src->ssa->parent_instr;
  106.    if (src_instr->type != nir_instr_type_alu)
  107.       return false;
  108.  
  109.    nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr);
  110.    if (!is_swizzleless_move(alu_instr))
  111.       return false;
  112.  
  113.    /* Don't let copy propagation land us with a phi that has more
  114.     * components in its source than it has in its destination.  That badly
  115.     * messes up out-of-ssa.
  116.     */
  117.    if (parent_instr && parent_instr->type == nir_instr_type_phi) {
  118.       nir_phi_instr *phi = nir_instr_as_phi(parent_instr);
  119.       assert(phi->dest.is_ssa);
  120.       if (phi->dest.ssa.num_components !=
  121.           alu_instr->src[0].src.ssa->num_components)
  122.          return false;
  123.    }
  124.  
  125.    if (parent_instr) {
  126.       nir_instr_rewrite_src(parent_instr, src,
  127.                             nir_src_for_ssa(alu_instr->src[0].src.ssa));
  128.    } else {
  129.       assert(src == &parent_if->condition);
  130.       nir_if_rewrite_condition(parent_if,
  131.                                nir_src_for_ssa(alu_instr->src[0].src.ssa));
  132.    }
  133.  
  134.    return true;
  135. }
  136.  
  137. static bool
  138. copy_prop_alu_src(nir_alu_instr *parent_alu_instr, unsigned index)
  139. {
  140.    nir_alu_src *src = &parent_alu_instr->src[index];
  141.    if (!src->src.is_ssa) {
  142.       if (src->src.reg.indirect)
  143.          return copy_prop_src(src->src.reg.indirect, &parent_alu_instr->instr,
  144.                               NULL);
  145.       return false;
  146.    }
  147.  
  148.    nir_instr *src_instr =  src->src.ssa->parent_instr;
  149.    if (src_instr->type != nir_instr_type_alu)
  150.       return false;
  151.  
  152.    nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr);
  153.    if (!is_move(alu_instr) && !is_vec(alu_instr))
  154.       return false;
  155.  
  156.    nir_ssa_def *def;
  157.    unsigned new_swizzle[4] = {0, 0, 0, 0};
  158.  
  159.    if (alu_instr->op == nir_op_fmov ||
  160.        alu_instr->op == nir_op_imov) {
  161.       for (unsigned i = 0; i < 4; i++)
  162.          new_swizzle[i] = alu_instr->src[0].swizzle[src->swizzle[i]];
  163.       def = alu_instr->src[0].src.ssa;
  164.    } else {
  165.       def = NULL;
  166.  
  167.       for (unsigned i = 0; i < 4; i++) {
  168.          if (!nir_alu_instr_channel_used(parent_alu_instr, index, i))
  169.             continue;
  170.  
  171.          nir_ssa_def *new_def = alu_instr->src[src->swizzle[i]].src.ssa;
  172.          if (def == NULL)
  173.             def = new_def;
  174.          else {
  175.             if (def != new_def)
  176.                return false;
  177.          }
  178.          new_swizzle[i] = alu_instr->src[src->swizzle[i]].swizzle[0];
  179.       }
  180.    }
  181.  
  182.    for (unsigned i = 0; i < 4; i++)
  183.       src->swizzle[i] = new_swizzle[i];
  184.  
  185.    nir_instr_rewrite_src(&parent_alu_instr->instr, &src->src,
  186.                          nir_src_for_ssa(def));
  187.  
  188.    return true;
  189. }
  190.  
  191. typedef struct {
  192.    nir_instr *parent_instr;
  193.    bool progress;
  194. } copy_prop_state;
  195.  
  196. static bool
  197. copy_prop_src_cb(nir_src *src, void *_state)
  198. {
  199.    copy_prop_state *state = (copy_prop_state *) _state;
  200.    while (copy_prop_src(src, state->parent_instr, NULL))
  201.       state->progress = true;
  202.  
  203.    return true;
  204. }
  205.  
  206. static bool
  207. copy_prop_instr(nir_instr *instr)
  208. {
  209.    if (instr->type == nir_instr_type_alu) {
  210.       nir_alu_instr *alu_instr = nir_instr_as_alu(instr);
  211.       bool progress = false;
  212.  
  213.       for (unsigned i = 0; i < nir_op_infos[alu_instr->op].num_inputs; i++)
  214.          while (copy_prop_alu_src(alu_instr, i))
  215.             progress = true;
  216.  
  217.       if (!alu_instr->dest.dest.is_ssa && alu_instr->dest.dest.reg.indirect)
  218.          while (copy_prop_src(alu_instr->dest.dest.reg.indirect, instr, NULL))
  219.             progress = true;
  220.  
  221.       return progress;
  222.    }
  223.  
  224.    copy_prop_state state;
  225.    state.parent_instr = instr;
  226.    state.progress = false;
  227.    nir_foreach_src(instr, copy_prop_src_cb, &state);
  228.  
  229.    return state.progress;
  230. }
  231.  
  232. static bool
  233. copy_prop_if(nir_if *if_stmt)
  234. {
  235.    return copy_prop_src(&if_stmt->condition, NULL, if_stmt);
  236. }
  237.  
  238. static bool
  239. copy_prop_block(nir_block *block, void *_state)
  240. {
  241.    bool *progress = (bool *) _state;
  242.  
  243.    nir_foreach_instr(block, instr) {
  244.       if (copy_prop_instr(instr))
  245.          *progress = true;
  246.    }
  247.  
  248.    if (block->cf_node.node.next != NULL && /* check that we aren't the end node */
  249.        !nir_cf_node_is_last(&block->cf_node) &&
  250.        nir_cf_node_next(&block->cf_node)->type == nir_cf_node_if) {
  251.       nir_if *if_stmt = nir_cf_node_as_if(nir_cf_node_next(&block->cf_node));
  252.       if (copy_prop_if(if_stmt))
  253.          *progress = true;
  254.    }
  255.  
  256.    return true;
  257. }
  258.  
  259. bool
  260. nir_copy_prop_impl(nir_function_impl *impl)
  261. {
  262.    bool progress = false;
  263.  
  264.    nir_foreach_block(impl, copy_prop_block, &progress);
  265.    return progress;
  266. }
  267.  
  268. bool
  269. nir_copy_prop(nir_shader *shader)
  270. {
  271.    bool progress = false;
  272.  
  273.    nir_foreach_overload(shader, overload) {
  274.       if (overload->impl && nir_copy_prop_impl(overload->impl))
  275.          progress = true;
  276.    }
  277.  
  278.    return progress;
  279. }
  280.