• 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 
30 static void
add_var_use_intrinsic(nir_intrinsic_instr * instr,struct set * live,nir_variable_mode modes)31 add_var_use_intrinsic(nir_intrinsic_instr *instr, struct set *live,
32                       nir_variable_mode modes)
33 {
34    unsigned num_vars = nir_intrinsic_infos[instr->intrinsic].num_variables;
35 
36    switch (instr->intrinsic) {
37    case nir_intrinsic_copy_var:
38       _mesa_set_add(live, instr->variables[1]->var);
39       /* Fall through */
40    case nir_intrinsic_store_var: {
41       /* The first source in both copy_var and store_var is the destination.
42        * If the variable is a local that never escapes the shader, then we
43        * don't mark it as live for just a store.
44        */
45       nir_variable_mode mode = instr->variables[0]->var->data.mode;
46       if (!(mode & (nir_var_local | nir_var_global | nir_var_shared)))
47          _mesa_set_add(live, instr->variables[0]->var);
48       break;
49    }
50 
51    /* This pass can't be used on I/O variables after they've been lowered. */
52    case nir_intrinsic_load_input:
53       assert(!(modes & nir_var_shader_in));
54       break;
55    case nir_intrinsic_store_output:
56       assert(!(modes & nir_var_shader_out));
57       break;
58 
59    default:
60       for (unsigned i = 0; i < num_vars; i++) {
61          _mesa_set_add(live, instr->variables[i]->var);
62       }
63       break;
64    }
65 }
66 
67 static void
add_var_use_call(nir_call_instr * instr,struct set * live)68 add_var_use_call(nir_call_instr *instr, struct set *live)
69 {
70    if (instr->return_deref != NULL) {
71       nir_variable *var = instr->return_deref->var;
72       _mesa_set_add(live, var);
73    }
74 
75    for (unsigned i = 0; i < instr->num_params; i++) {
76       nir_variable *var = instr->params[i]->var;
77       _mesa_set_add(live, var);
78    }
79 }
80 
81 static void
add_var_use_tex(nir_tex_instr * instr,struct set * live)82 add_var_use_tex(nir_tex_instr *instr, struct set *live)
83 {
84    if (instr->texture != NULL) {
85       nir_variable *var = instr->texture->var;
86       _mesa_set_add(live, var);
87    }
88 
89    if (instr->sampler != NULL) {
90       nir_variable *var = instr->sampler->var;
91       _mesa_set_add(live, var);
92    }
93 }
94 
95 static void
add_var_use_shader(nir_shader * shader,struct set * live,nir_variable_mode modes)96 add_var_use_shader(nir_shader *shader, struct set *live, nir_variable_mode modes)
97 {
98    nir_foreach_function(function, shader) {
99       if (function->impl) {
100          nir_foreach_block(block, function->impl) {
101             nir_foreach_instr(instr, block) {
102                switch(instr->type) {
103                case nir_instr_type_intrinsic:
104                   add_var_use_intrinsic(nir_instr_as_intrinsic(instr), live,
105                                         modes);
106                   break;
107 
108                case nir_instr_type_call:
109                   add_var_use_call(nir_instr_as_call(instr), live);
110                   break;
111 
112                case nir_instr_type_tex:
113                   add_var_use_tex(nir_instr_as_tex(instr), live);
114                   break;
115 
116                default:
117                   break;
118                }
119             }
120          }
121       }
122    }
123 }
124 
125 static void
remove_dead_var_writes(nir_shader * shader,struct set * live)126 remove_dead_var_writes(nir_shader *shader, struct set *live)
127 {
128    nir_foreach_function(function, shader) {
129       if (!function->impl)
130          continue;
131 
132       nir_foreach_block(block, function->impl) {
133          nir_foreach_instr_safe(instr, block) {
134             if (instr->type != nir_instr_type_intrinsic)
135                continue;
136 
137             nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
138             if (intrin->intrinsic != nir_intrinsic_copy_var &&
139                 intrin->intrinsic != nir_intrinsic_store_var)
140                continue;
141 
142             /* Stores to dead variables need to be removed */
143             if (intrin->variables[0]->var->data.mode == 0)
144                nir_instr_remove(instr);
145          }
146       }
147    }
148 }
149 
150 static bool
remove_dead_vars(struct exec_list * var_list,struct set * live)151 remove_dead_vars(struct exec_list *var_list, struct set *live)
152 {
153    bool progress = false;
154 
155    foreach_list_typed_safe(nir_variable, var, node, var_list) {
156       struct set_entry *entry = _mesa_set_search(live, var);
157       if (entry == NULL) {
158          /* Mark this variable as used by setting the mode to 0 */
159          var->data.mode = 0;
160          exec_node_remove(&var->node);
161          progress = true;
162       }
163    }
164 
165    return progress;
166 }
167 
168 bool
nir_remove_dead_variables(nir_shader * shader,nir_variable_mode modes)169 nir_remove_dead_variables(nir_shader *shader, nir_variable_mode modes)
170 {
171    bool progress = false;
172    struct set *live =
173       _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal);
174 
175    add_var_use_shader(shader, live, modes);
176 
177    if (modes & nir_var_uniform)
178       progress = remove_dead_vars(&shader->uniforms, live) || progress;
179 
180    if (modes & nir_var_shader_in)
181       progress = remove_dead_vars(&shader->inputs, live) || progress;
182 
183    if (modes & nir_var_shader_out)
184       progress = remove_dead_vars(&shader->outputs, live) || progress;
185 
186    if (modes & nir_var_global)
187       progress = remove_dead_vars(&shader->globals, live) || progress;
188 
189    if (modes & nir_var_system_value)
190       progress = remove_dead_vars(&shader->system_values, live) || progress;
191 
192    if (modes & nir_var_shared)
193       progress = remove_dead_vars(&shader->shared, live) || progress;
194 
195    if (modes & nir_var_local) {
196       nir_foreach_function(function, shader) {
197          if (function->impl) {
198             if (remove_dead_vars(&function->impl->locals, live))
199                progress = true;
200          }
201       }
202    }
203 
204    if (progress) {
205       remove_dead_var_writes(shader, live);
206 
207       nir_foreach_function(function, shader) {
208          if (function->impl) {
209             nir_metadata_preserve(function->impl, nir_metadata_block_index |
210                                                   nir_metadata_dominance);
211          }
212       }
213    }
214 
215    _mesa_set_destroy(live, NULL);
216    return progress;
217 }
218