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
)
57 is_swizzleless_move(nir_alu_instr
*instr
)
62 for (unsigned i
= 0; i
< 4; i
++) {
63 if (!((instr
->dest
.write_mask
>> i
) & 1))
65 if (instr
->src
[0].swizzle
[i
] != i
)
72 static bool is_vec(nir_alu_instr
*instr
)
74 for (unsigned i
= 0; i
< nir_op_infos
[instr
->op
].num_inputs
; i
++)
75 if (!instr
->src
[i
].src
.is_ssa
)
78 return instr
->op
== nir_op_vec2
||
79 instr
->op
== nir_op_vec3
||
80 instr
->op
== nir_op_vec4
;
89 search_def(nir_src
*src
, void *_state
)
91 search_def_state
*state
= (search_def_state
*) _state
;
93 if (src
->is_ssa
&& src
->ssa
== state
->def
)
100 rewrite_src_instr(nir_src
*src
, nir_ssa_def
*new_def
, nir_instr
*parent_instr
)
102 nir_ssa_def
*old_def
= src
->ssa
;
107 * The instruction could still use the old definition in one of its other
108 * sources, so only remove the instruction from the uses if there are no
112 search_def_state search_state
;
113 search_state
.def
= old_def
;
114 search_state
.found
= false;
115 nir_foreach_src(parent_instr
, search_def
, &search_state
);
116 if (!search_state
.found
) {
117 struct set_entry
*entry
= _mesa_set_search(old_def
->uses
, parent_instr
);
119 _mesa_set_remove(old_def
->uses
, entry
);
122 _mesa_set_add(new_def
->uses
, parent_instr
);
126 rewrite_src_if(nir_if
*if_stmt
, nir_ssa_def
*new_def
)
128 nir_ssa_def
*old_def
= if_stmt
->condition
.ssa
;
130 if_stmt
->condition
.ssa
= new_def
;
132 struct set_entry
*entry
= _mesa_set_search(old_def
->if_uses
, if_stmt
);
134 _mesa_set_remove(old_def
->if_uses
, entry
);
136 _mesa_set_add(new_def
->if_uses
, if_stmt
);
140 copy_prop_src(nir_src
*src
, nir_instr
*parent_instr
, nir_if
*parent_if
)
143 if (src
->reg
.indirect
)
144 return copy_prop_src(src
, parent_instr
, parent_if
);
148 nir_instr
*src_instr
= src
->ssa
->parent_instr
;
149 if (src_instr
->type
!= nir_instr_type_alu
)
152 nir_alu_instr
*alu_instr
= nir_instr_as_alu(src_instr
);
153 if (!is_swizzleless_move(alu_instr
))
156 /* Don't let copy propagation land us with a phi that has more
157 * components in its source than it has in its destination. That badly
158 * messes up out-of-ssa.
160 if (parent_instr
&& parent_instr
->type
== nir_instr_type_phi
) {
161 nir_phi_instr
*phi
= nir_instr_as_phi(parent_instr
);
162 assert(phi
->dest
.is_ssa
);
163 if (phi
->dest
.ssa
.num_components
!=
164 alu_instr
->src
[0].src
.ssa
->num_components
)
169 rewrite_src_instr(src
, alu_instr
->src
[0].src
.ssa
, parent_instr
);
171 rewrite_src_if(parent_if
, alu_instr
->src
[0].src
.ssa
);
177 copy_prop_alu_src(nir_alu_instr
*parent_alu_instr
, unsigned index
)
179 nir_alu_src
*src
= &parent_alu_instr
->src
[index
];
180 if (!src
->src
.is_ssa
) {
181 if (src
->src
.reg
.indirect
)
182 return copy_prop_src(src
->src
.reg
.indirect
, &parent_alu_instr
->instr
,
187 nir_instr
*src_instr
= src
->src
.ssa
->parent_instr
;
188 if (src_instr
->type
!= nir_instr_type_alu
)
191 nir_alu_instr
*alu_instr
= nir_instr_as_alu(src_instr
);
192 if (!is_move(alu_instr
) && !is_vec(alu_instr
))
196 unsigned new_swizzle
[4] = {0, 0, 0, 0};
198 if (alu_instr
->op
== nir_op_fmov
||
199 alu_instr
->op
== nir_op_imov
) {
200 for (unsigned i
= 0; i
< 4; i
++)
201 new_swizzle
[i
] = alu_instr
->src
[0].swizzle
[src
->swizzle
[i
]];
202 def
= alu_instr
->src
[0].src
.ssa
;
206 for (unsigned i
= 0; i
< 4; i
++) {
207 if (!nir_alu_instr_channel_used(parent_alu_instr
, index
, i
))
210 nir_ssa_def
*new_def
= alu_instr
->src
[src
->swizzle
[i
]].src
.ssa
;
217 new_swizzle
[i
] = alu_instr
->src
[src
->swizzle
[i
]].swizzle
[0];
221 for (unsigned i
= 0; i
< 4; i
++)
222 src
->swizzle
[i
] = new_swizzle
[i
];
224 rewrite_src_instr(&src
->src
, def
, &parent_alu_instr
->instr
);
230 nir_instr
*parent_instr
;
235 copy_prop_src_cb(nir_src
*src
, void *_state
)
237 copy_prop_state
*state
= (copy_prop_state
*) _state
;
238 while (copy_prop_src(src
, state
->parent_instr
, NULL
))
239 state
->progress
= true;
245 copy_prop_instr(nir_instr
*instr
)
247 if (instr
->type
== nir_instr_type_alu
) {
248 nir_alu_instr
*alu_instr
= nir_instr_as_alu(instr
);
249 bool progress
= false;
251 for (unsigned i
= 0; i
< nir_op_infos
[alu_instr
->op
].num_inputs
; i
++)
252 while (copy_prop_alu_src(alu_instr
, i
))
255 if (!alu_instr
->dest
.dest
.is_ssa
&& alu_instr
->dest
.dest
.reg
.indirect
)
256 while (copy_prop_src(alu_instr
->dest
.dest
.reg
.indirect
, instr
, NULL
))
262 copy_prop_state state
;
263 state
.parent_instr
= instr
;
264 state
.progress
= false;
265 nir_foreach_src(instr
, copy_prop_src_cb
, &state
);
267 return state
.progress
;
271 copy_prop_if(nir_if
*if_stmt
)
273 return copy_prop_src(&if_stmt
->condition
, NULL
, if_stmt
);
277 copy_prop_block(nir_block
*block
, void *_state
)
279 bool *progress
= (bool *) _state
;
281 nir_foreach_instr(block
, instr
) {
282 if (copy_prop_instr(instr
))
286 if (block
->cf_node
.node
.next
!= NULL
&& /* check that we aren't the end node */
287 !nir_cf_node_is_last(&block
->cf_node
) &&
288 nir_cf_node_next(&block
->cf_node
)->type
== nir_cf_node_if
) {
289 nir_if
*if_stmt
= nir_cf_node_as_if(nir_cf_node_next(&block
->cf_node
));
290 if (copy_prop_if(if_stmt
))
298 nir_copy_prop_impl(nir_function_impl
*impl
)
300 bool progress
= false;
302 nir_foreach_block(impl
, copy_prop_block
, &progress
);
307 nir_copy_prop(nir_shader
*shader
)
309 bool progress
= false;
311 nir_foreach_overload(shader
, overload
) {
312 if (overload
->impl
&& nir_copy_prop_impl(overload
->impl
))