2 * Copyright © 2015 Intel Corporation
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:
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
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
25 * Implements a pass that lowers output variables to a temporary plus an
26 * output variable with a single copy at each exit point of the shader.
27 * This way the output variable is only ever written.
32 struct lower_io_state
{
34 struct exec_list old_outputs
;
38 emit_output_copies(nir_cursor cursor
, struct lower_io_state
*state
)
40 assert(exec_list_length(&state
->shader
->outputs
) ==
41 exec_list_length(&state
->old_outputs
));
43 foreach_two_lists(out_node
, &state
->shader
->outputs
,
44 temp_node
, &state
->old_outputs
) {
45 nir_variable
*output
= exec_node_data(nir_variable
, out_node
, node
);
46 nir_variable
*temp
= exec_node_data(nir_variable
, temp_node
, node
);
48 nir_intrinsic_instr
*copy
=
49 nir_intrinsic_instr_create(state
->shader
, nir_intrinsic_copy_var
);
50 copy
->variables
[0] = nir_deref_var_create(copy
, output
);
51 copy
->variables
[1] = nir_deref_var_create(copy
, temp
);
53 nir_instr_insert(cursor
, ©
->instr
);
58 nir_lower_io_to_temporaries(nir_shader
*shader
, nir_function
*entrypoint
)
60 struct lower_io_state state
;
62 if (shader
->stage
== MESA_SHADER_TESS_CTRL
)
65 state
.shader
= shader
;
66 exec_list_move_nodes_to(&shader
->outputs
, &state
.old_outputs
);
68 /* Walk over all of the outputs turn each output into a temporary and
69 * make a new variable for the actual output.
71 nir_foreach_variable(var
, &state
.old_outputs
) {
72 nir_variable
*output
= ralloc(shader
, nir_variable
);
73 memcpy(output
, var
, sizeof *output
);
75 /* The orignal is now the temporary */
76 nir_variable
*temp
= var
;
78 /* Reparent the name to the new variable */
79 ralloc_steal(output
, output
->name
);
81 /* Reparent the constant initializer (if any) */
82 ralloc_steal(output
, output
->constant_initializer
);
84 /* Give the output a new name with @out-temp appended */
85 temp
->name
= ralloc_asprintf(var
, "%s@out-temp", output
->name
);
86 temp
->data
.mode
= nir_var_global
;
87 temp
->constant_initializer
= NULL
;
89 exec_list_push_tail(&shader
->outputs
, &output
->node
);
92 nir_foreach_function(function
, shader
) {
93 if (function
->impl
== NULL
)
96 if (shader
->stage
== MESA_SHADER_GEOMETRY
) {
97 /* For geometry shaders, we have to emit the output copies right
98 * before each EmitVertex call.
100 nir_foreach_block(block
, function
->impl
) {
101 nir_foreach_instr(instr
, block
) {
102 if (instr
->type
!= nir_instr_type_intrinsic
)
105 nir_intrinsic_instr
*intrin
= nir_instr_as_intrinsic(instr
);
106 if (intrin
->intrinsic
== nir_intrinsic_emit_vertex
) {
107 emit_output_copies(nir_before_instr(&intrin
->instr
),
112 } else if (function
== entrypoint
) {
113 /* For all other shader types, we need to do the copies right before
114 * the jumps to the end block.
116 struct set_entry
*block_entry
;
117 set_foreach(function
->impl
->end_block
->predecessors
, block_entry
) {
118 struct nir_block
*block
= (void *)block_entry
->key
;
119 emit_output_copies(nir_after_block_before_jump(block
), &state
);
123 nir_metadata_preserve(function
->impl
, nir_metadata_block_index
|
124 nir_metadata_dominance
);
127 exec_list_append(&shader
->globals
, &state
.old_outputs
);