2 * Copyright © 2014 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
24 * Connor Abbott (cwabbott0@gmail.com)
29 #include <main/imports.h>
32 * SSA-based copy propagation
35 static bool is_move(nir_alu_instr
*instr
)
37 if (instr
->op
!= nir_op_fmov
&&
38 instr
->op
!= nir_op_imov
)
41 if (instr
->dest
.saturate
)
44 /* we handle modifiers in a separate pass */
46 if (instr
->src
[0].abs
|| instr
->src
[0].negate
)
49 if (!instr
->src
[0].src
.is_ssa
)
56 static bool is_vec(nir_alu_instr
*instr
)
58 for (unsigned i
= 0; i
< nir_op_infos
[instr
->op
].num_inputs
; i
++)
59 if (!instr
->src
[i
].src
.is_ssa
)
62 return instr
->op
== nir_op_vec2
||
63 instr
->op
== nir_op_vec3
||
64 instr
->op
== nir_op_vec4
;
68 is_swizzleless_move(nir_alu_instr
*instr
)
71 for (unsigned i
= 0; i
< 4; i
++) {
72 if (!((instr
->dest
.write_mask
>> i
) & 1))
74 if (instr
->src
[0].swizzle
[i
] != i
)
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
)
85 def
= instr
->src
[i
].src
.ssa
;
86 } else if (instr
->src
[i
].src
.ssa
!= def
) {
102 search_def(nir_src
*src
, void *_state
)
104 search_def_state
*state
= (search_def_state
*) _state
;
106 if (src
->is_ssa
&& src
->ssa
== state
->def
)
113 rewrite_src_instr(nir_src
*src
, nir_ssa_def
*new_def
, nir_instr
*parent_instr
)
115 nir_ssa_def
*old_def
= src
->ssa
;
120 * The instruction could still use the old definition in one of its other
121 * sources, so only remove the instruction from the uses if there are no
125 search_def_state search_state
;
126 search_state
.def
= old_def
;
127 search_state
.found
= false;
128 nir_foreach_src(parent_instr
, search_def
, &search_state
);
129 if (!search_state
.found
) {
130 struct set_entry
*entry
= _mesa_set_search(old_def
->uses
, parent_instr
);
132 _mesa_set_remove(old_def
->uses
, entry
);
135 _mesa_set_add(new_def
->uses
, parent_instr
);
139 rewrite_src_if(nir_if
*if_stmt
, nir_ssa_def
*new_def
)
141 nir_ssa_def
*old_def
= if_stmt
->condition
.ssa
;
143 if_stmt
->condition
.ssa
= new_def
;
145 struct set_entry
*entry
= _mesa_set_search(old_def
->if_uses
, if_stmt
);
147 _mesa_set_remove(old_def
->if_uses
, entry
);
149 _mesa_set_add(new_def
->if_uses
, if_stmt
);
153 copy_prop_src(nir_src
*src
, nir_instr
*parent_instr
, nir_if
*parent_if
)
156 if (src
->reg
.indirect
)
157 return copy_prop_src(src
, parent_instr
, parent_if
);
161 nir_instr
*src_instr
= src
->ssa
->parent_instr
;
162 if (src_instr
->type
!= nir_instr_type_alu
)
165 nir_alu_instr
*alu_instr
= nir_instr_as_alu(src_instr
);
166 if (!is_swizzleless_move(alu_instr
))
169 /* Don't let copy propagation land us with a phi that has more
170 * components in its source than it has in its destination. That badly
171 * messes up out-of-ssa.
173 if (parent_instr
&& parent_instr
->type
== nir_instr_type_phi
) {
174 nir_phi_instr
*phi
= nir_instr_as_phi(parent_instr
);
175 assert(phi
->dest
.is_ssa
);
176 if (phi
->dest
.ssa
.num_components
!=
177 alu_instr
->src
[0].src
.ssa
->num_components
)
182 rewrite_src_instr(src
, alu_instr
->src
[0].src
.ssa
, parent_instr
);
184 rewrite_src_if(parent_if
, alu_instr
->src
[0].src
.ssa
);
190 copy_prop_alu_src(nir_alu_instr
*parent_alu_instr
, unsigned index
)
192 nir_alu_src
*src
= &parent_alu_instr
->src
[index
];
193 if (!src
->src
.is_ssa
) {
194 if (src
->src
.reg
.indirect
)
195 return copy_prop_src(src
->src
.reg
.indirect
, &parent_alu_instr
->instr
,
200 nir_instr
*src_instr
= src
->src
.ssa
->parent_instr
;
201 if (src_instr
->type
!= nir_instr_type_alu
)
204 nir_alu_instr
*alu_instr
= nir_instr_as_alu(src_instr
);
205 if (!is_move(alu_instr
) && !is_vec(alu_instr
))
209 unsigned new_swizzle
[4] = {0, 0, 0, 0};
211 if (alu_instr
->op
== nir_op_fmov
||
212 alu_instr
->op
== nir_op_imov
) {
213 for (unsigned i
= 0; i
< 4; i
++)
214 new_swizzle
[i
] = alu_instr
->src
[0].swizzle
[src
->swizzle
[i
]];
215 def
= alu_instr
->src
[0].src
.ssa
;
219 for (unsigned i
= 0; i
< 4; i
++) {
220 if (!nir_alu_instr_channel_used(parent_alu_instr
, index
, i
))
223 nir_ssa_def
*new_def
= alu_instr
->src
[src
->swizzle
[i
]].src
.ssa
;
230 new_swizzle
[i
] = alu_instr
->src
[src
->swizzle
[i
]].swizzle
[0];
234 for (unsigned i
= 0; i
< 4; i
++)
235 src
->swizzle
[i
] = new_swizzle
[i
];
237 rewrite_src_instr(&src
->src
, def
, &parent_alu_instr
->instr
);
243 nir_instr
*parent_instr
;
248 copy_prop_src_cb(nir_src
*src
, void *_state
)
250 copy_prop_state
*state
= (copy_prop_state
*) _state
;
251 while (copy_prop_src(src
, state
->parent_instr
, NULL
))
252 state
->progress
= true;
258 copy_prop_instr(nir_instr
*instr
)
260 if (instr
->type
== nir_instr_type_alu
) {
261 nir_alu_instr
*alu_instr
= nir_instr_as_alu(instr
);
262 bool progress
= false;
264 for (unsigned i
= 0; i
< nir_op_infos
[alu_instr
->op
].num_inputs
; i
++)
265 while (copy_prop_alu_src(alu_instr
, i
))
268 if (!alu_instr
->dest
.dest
.is_ssa
&& alu_instr
->dest
.dest
.reg
.indirect
)
269 while (copy_prop_src(alu_instr
->dest
.dest
.reg
.indirect
, instr
, NULL
))
275 copy_prop_state state
;
276 state
.parent_instr
= instr
;
277 state
.progress
= false;
278 nir_foreach_src(instr
, copy_prop_src_cb
, &state
);
280 return state
.progress
;
284 copy_prop_if(nir_if
*if_stmt
)
286 return copy_prop_src(&if_stmt
->condition
, NULL
, if_stmt
);
290 copy_prop_block(nir_block
*block
, void *_state
)
292 bool *progress
= (bool *) _state
;
294 nir_foreach_instr(block
, instr
) {
295 if (copy_prop_instr(instr
))
299 if (block
->cf_node
.node
.next
!= NULL
&& /* check that we aren't the end node */
300 !nir_cf_node_is_last(&block
->cf_node
) &&
301 nir_cf_node_next(&block
->cf_node
)->type
== nir_cf_node_if
) {
302 nir_if
*if_stmt
= nir_cf_node_as_if(nir_cf_node_next(&block
->cf_node
));
303 if (copy_prop_if(if_stmt
))
311 nir_copy_prop_impl(nir_function_impl
*impl
)
313 bool progress
= false;
315 nir_foreach_block(impl
, copy_prop_block
, &progress
);
320 nir_copy_prop(nir_shader
*shader
)
322 bool progress
= false;
324 nir_foreach_overload(shader
, overload
) {
325 if (overload
->impl
&& nir_copy_prop_impl(overload
->impl
))