nir/algebraic: Make algebraic_parser_test.sh executable.
[mesa.git] / src / compiler / nir / nir_lower_io_to_temporaries.c
1 /*
2 * Copyright © 2015 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
24 /*
25 * Implements a pass that lowers output and/or input variables to a
26 * temporary plus an output variable with a single copy at each exit
27 * point of the shader and/or an input variable with a single copy
28 * at the entrance point of the shader. This way the output variable
29 * is only ever written once and/or input is only read once, and there
30 * are no indirect outut/input accesses.
31 */
32
33 #include "nir.h"
34 #include "nir_builder.h"
35
36 struct lower_io_state {
37 nir_shader *shader;
38 nir_function_impl *entrypoint;
39 struct exec_list old_outputs;
40 struct exec_list old_inputs;
41 };
42
43 static void
44 emit_copies(nir_builder *b, struct exec_list *dest_vars,
45 struct exec_list *src_vars)
46 {
47 assert(exec_list_length(dest_vars) == exec_list_length(src_vars));
48
49 foreach_two_lists(dest_node, dest_vars, src_node, src_vars) {
50 nir_variable *dest = exec_node_data(nir_variable, dest_node, node);
51 nir_variable *src = exec_node_data(nir_variable, src_node, node);
52
53 /* No need to copy the contents of a non-fb_fetch_output output variable
54 * to the temporary allocated for it, since its initial value is
55 * undefined.
56 */
57 if (src->data.mode == nir_var_shader_out &&
58 !src->data.fb_fetch_output)
59 continue;
60
61 /* Can't copy the contents of the temporary back to a read-only
62 * interface variable. The value of the temporary won't have been
63 * modified by the shader anyway.
64 */
65 if (dest->data.read_only)
66 continue;
67
68 nir_copy_var(b, dest, src);
69 }
70 }
71
72 static void
73 emit_output_copies_impl(struct lower_io_state *state, nir_function_impl *impl)
74 {
75 nir_builder b;
76 nir_builder_init(&b, impl);
77
78 if (state->shader->info.stage == MESA_SHADER_GEOMETRY) {
79 /* For geometry shaders, we have to emit the output copies right
80 * before each EmitVertex call.
81 */
82 nir_foreach_block(block, impl) {
83 nir_foreach_instr(instr, block) {
84 if (instr->type != nir_instr_type_intrinsic)
85 continue;
86
87 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
88 if (intrin->intrinsic == nir_intrinsic_emit_vertex) {
89 b.cursor = nir_before_instr(&intrin->instr);
90 emit_copies(&b, &state->shader->outputs, &state->old_outputs);
91 }
92 }
93 }
94 } else if (impl == state->entrypoint) {
95 b.cursor = nir_before_block(nir_start_block(impl));
96 emit_copies(&b, &state->old_outputs, &state->shader->outputs);
97
98 /* For all other shader types, we need to do the copies right before
99 * the jumps to the end block.
100 */
101 set_foreach(impl->end_block->predecessors, block_entry) {
102 struct nir_block *block = (void *)block_entry->key;
103 b.cursor = nir_after_block_before_jump(block);
104 emit_copies(&b, &state->shader->outputs, &state->old_outputs);
105 }
106 }
107 }
108
109 static void
110 emit_input_copies_impl(struct lower_io_state *state, nir_function_impl *impl)
111 {
112 if (impl == state->entrypoint) {
113 nir_builder b;
114 nir_builder_init(&b, impl);
115 b.cursor = nir_before_block(nir_start_block(impl));
116 emit_copies(&b, &state->old_inputs, &state->shader->inputs);
117 }
118 }
119
120 static nir_variable *
121 create_shadow_temp(struct lower_io_state *state, nir_variable *var)
122 {
123 nir_variable *nvar = ralloc(state->shader, nir_variable);
124 memcpy(nvar, var, sizeof *nvar);
125
126 /* The original is now the temporary */
127 nir_variable *temp = var;
128
129 /* Reparent the name to the new variable */
130 ralloc_steal(nvar, nvar->name);
131
132 assert(nvar->constant_initializer == NULL);
133
134 /* Give the original a new name with @<mode>-temp appended */
135 const char *mode = (temp->data.mode == nir_var_shader_in) ? "in" : "out";
136 temp->name = ralloc_asprintf(var, "%s@%s-temp", mode, nvar->name);
137 temp->data.mode = nir_var_global;
138 temp->data.read_only = false;
139 temp->data.fb_fetch_output = false;
140 temp->data.compact = false;
141
142 return nvar;
143 }
144
145 void
146 nir_lower_io_to_temporaries(nir_shader *shader, nir_function_impl *entrypoint,
147 bool outputs, bool inputs)
148 {
149 struct lower_io_state state;
150
151 if (shader->info.stage == MESA_SHADER_TESS_CTRL)
152 return;
153
154 state.shader = shader;
155 state.entrypoint = entrypoint;
156
157 if (inputs)
158 exec_list_move_nodes_to(&shader->inputs, &state.old_inputs);
159 else
160 exec_list_make_empty(&state.old_inputs);
161
162 if (outputs)
163 exec_list_move_nodes_to(&shader->outputs, &state.old_outputs);
164 else
165 exec_list_make_empty(&state.old_outputs);
166
167 /* Walk over all of the outputs turn each output into a temporary and
168 * make a new variable for the actual output.
169 */
170 nir_foreach_variable(var, &state.old_outputs) {
171 nir_variable *output = create_shadow_temp(&state, var);
172 exec_list_push_tail(&shader->outputs, &output->node);
173 }
174
175 /* and same for inputs: */
176 nir_foreach_variable(var, &state.old_inputs) {
177 nir_variable *input = create_shadow_temp(&state, var);
178 exec_list_push_tail(&shader->inputs, &input->node);
179 }
180
181 nir_foreach_function(function, shader) {
182 if (function->impl == NULL)
183 continue;
184
185 if (inputs)
186 emit_input_copies_impl(&state, function->impl);
187
188 if (outputs)
189 emit_output_copies_impl(&state, function->impl);
190
191 nir_metadata_preserve(function->impl, nir_metadata_block_index |
192 nir_metadata_dominance);
193 }
194
195 exec_list_append(&shader->globals, &state.old_inputs);
196 exec_list_append(&shader->globals, &state.old_outputs);
197
198 nir_fixup_deref_modes(shader);
199 }