• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "nir_builder.h"
30 
31 /**
32  * SSA-based copy propagation
33  */
34 
35 static bool
is_swizzleless_move(nir_alu_instr * instr)36 is_swizzleless_move(nir_alu_instr *instr)
37 {
38    unsigned num_comp = instr->dest.dest.ssa.num_components;
39 
40    if (instr->src[0].src.ssa->num_components != num_comp)
41       return false;
42 
43    if (instr->op == nir_op_mov) {
44       for (unsigned i = 0; i < num_comp; i++) {
45          if (instr->src[0].swizzle[i] != i)
46             return false;
47       }
48    } else {
49       for (unsigned i = 0; i < num_comp; i++) {
50          if (instr->src[i].swizzle[0] != i ||
51              instr->src[i].src.ssa != instr->src[0].src.ssa)
52             return false;
53       }
54    }
55 
56    return true;
57 }
58 
59 static bool
rewrite_to_vec(nir_function_impl * impl,nir_alu_instr * mov,nir_alu_instr * vec)60 rewrite_to_vec(nir_function_impl *impl, nir_alu_instr *mov, nir_alu_instr *vec)
61 {
62    if (mov->op != nir_op_mov)
63       return false;
64 
65    nir_builder b;
66    nir_builder_init(&b, impl);
67    b.cursor = nir_after_instr(&mov->instr);
68 
69    unsigned num_comp = mov->dest.dest.ssa.num_components;
70    nir_alu_instr *new_vec = nir_alu_instr_create(b.shader, nir_op_vec(num_comp));
71    for (unsigned i = 0; i < num_comp; i++)
72       new_vec->src[i] = vec->src[mov->src[0].swizzle[i]];
73 
74    nir_ssa_def *new = nir_builder_alu_instr_finish_and_insert(&b, new_vec);
75    nir_ssa_def_rewrite_uses(&mov->dest.dest.ssa, new);
76 
77    /* If we remove "mov" and it's the next instruction in the
78     * nir_foreach_instr_safe() loop, then we would end copy-propagation early. */
79 
80    return true;
81 }
82 
83 static bool
copy_propagate_alu(nir_function_impl * impl,nir_alu_src * src,nir_alu_instr * copy)84 copy_propagate_alu(nir_function_impl *impl, nir_alu_src *src, nir_alu_instr *copy)
85 {
86    nir_ssa_def *def = NULL;
87    nir_alu_instr *user = nir_instr_as_alu(src->src.parent_instr);
88    unsigned src_idx = src - user->src;
89    assert(src_idx < nir_op_infos[user->op].num_inputs);
90    unsigned num_comp = nir_ssa_alu_instr_src_components(user, src_idx);
91 
92    if (copy->op == nir_op_mov) {
93       def = copy->src[0].src.ssa;
94 
95       for (unsigned i = 0; i < num_comp; i++)
96          src->swizzle[i] = copy->src[0].swizzle[src->swizzle[i]];
97    } else {
98       def = copy->src[src->swizzle[0]].src.ssa;
99 
100       for (unsigned i = 1; i < num_comp; i++) {
101          if (copy->src[src->swizzle[i]].src.ssa != def)
102             return rewrite_to_vec(impl, user, copy);
103       }
104 
105       for (unsigned i = 0; i < num_comp; i++)
106          src->swizzle[i] = copy->src[src->swizzle[i]].swizzle[0];
107    }
108 
109    nir_instr_rewrite_src_ssa(src->src.parent_instr, &src->src, def);
110 
111    return true;
112 }
113 
114 static bool
copy_propagate(nir_src * src,nir_alu_instr * copy)115 copy_propagate(nir_src *src, nir_alu_instr *copy)
116 {
117    if (!is_swizzleless_move(copy))
118       return false;
119 
120    nir_instr_rewrite_src_ssa(src->parent_instr, src, copy->src[0].src.ssa);
121 
122    return true;
123 }
124 
125 static bool
copy_propagate_if(nir_src * src,nir_alu_instr * copy)126 copy_propagate_if(nir_src *src, nir_alu_instr *copy)
127 {
128    if (!is_swizzleless_move(copy))
129       return false;
130 
131    nir_if_rewrite_condition_ssa(src->parent_if, src, copy->src[0].src.ssa);
132 
133    return true;
134 }
135 
136 static bool
copy_prop_instr(nir_function_impl * impl,nir_instr * instr)137 copy_prop_instr(nir_function_impl *impl, nir_instr *instr)
138 {
139    if (instr->type != nir_instr_type_alu)
140       return false;
141 
142    nir_alu_instr *mov = nir_instr_as_alu(instr);
143 
144    if (!nir_alu_instr_is_copy(mov))
145       return false;
146 
147    bool progress = false;
148 
149    nir_foreach_use_safe(src, &mov->dest.dest.ssa) {
150       if (src->parent_instr->type == nir_instr_type_alu)
151          progress |= copy_propagate_alu(impl, container_of(src, nir_alu_src, src), mov);
152       else
153          progress |= copy_propagate(src, mov);
154    }
155 
156    nir_foreach_if_use_safe(src, &mov->dest.dest.ssa)
157       progress |= copy_propagate_if(src, mov);
158 
159    if (progress && nir_ssa_def_is_unused(&mov->dest.dest.ssa))
160       nir_instr_remove(&mov->instr);
161 
162    return progress;
163 }
164 
165 bool
nir_copy_prop_impl(nir_function_impl * impl)166 nir_copy_prop_impl(nir_function_impl *impl)
167 {
168    bool progress = false;
169 
170    nir_foreach_block(block, impl) {
171       nir_foreach_instr_safe(instr, block) {
172          progress |= copy_prop_instr(impl, instr);
173       }
174    }
175 
176    if (progress) {
177       nir_metadata_preserve(impl, nir_metadata_block_index |
178                                   nir_metadata_dominance);
179    } else {
180       nir_metadata_preserve(impl, nir_metadata_all);
181    }
182 
183    return progress;
184 }
185 
186 bool
nir_copy_prop(nir_shader * shader)187 nir_copy_prop(nir_shader *shader)
188 {
189    bool progress = false;
190 
191    nir_foreach_function(function, shader) {
192       if (function->impl && nir_copy_prop_impl(function->impl))
193          progress = true;
194    }
195 
196    return progress;
197 }
198