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 ([email protected])
25 *
26 */
27
28 #include "nir.h"
29 #include "nir_builder.h"
30
31 /**
32 * SSA-based copy propagation
33 */
34
35 static bool
is_swizzleless_move(nir_alu_instr * instr)36 is_swizzleless_move(nir_alu_instr *instr)
37 {
38 unsigned num_comp = instr->def.num_components;
39
40 if (instr->src[0].src.ssa->num_components != num_comp)
41 return false;
42
43 if (instr->op == nir_op_mov) {
44 for (unsigned i = 0; i < num_comp; i++) {
45 if (instr->src[0].swizzle[i] != i)
46 return false;
47 }
48 } else {
49 for (unsigned i = 0; i < num_comp; i++) {
50 if (instr->src[i].swizzle[0] != i ||
51 instr->src[i].src.ssa != instr->src[0].src.ssa)
52 return false;
53 }
54 }
55
56 return true;
57 }
58
59 static bool
rewrite_to_vec(nir_alu_instr * mov,nir_alu_instr * vec)60 rewrite_to_vec(nir_alu_instr *mov, nir_alu_instr *vec)
61 {
62 if (mov->op != nir_op_mov)
63 return false;
64
65 nir_builder b = nir_builder_at(nir_after_instr(&mov->instr));
66
67 unsigned num_comp = mov->def.num_components;
68 nir_alu_instr *new_vec = nir_alu_instr_create(b.shader, nir_op_vec(num_comp));
69 for (unsigned i = 0; i < num_comp; i++)
70 new_vec->src[i] = vec->src[mov->src[0].swizzle[i]];
71
72 nir_def *new = nir_builder_alu_instr_finish_and_insert(&b, new_vec);
73 nir_def_rewrite_uses(&mov->def, new);
74
75 /* If we remove "mov" and it's the next instruction in the
76 * nir_foreach_instr_safe() loop, then we would end copy-propagation early. */
77
78 return true;
79 }
80
81 static bool
copy_propagate_alu(nir_alu_src * src,nir_alu_instr * copy)82 copy_propagate_alu(nir_alu_src *src, nir_alu_instr *copy)
83 {
84 nir_def *def = NULL;
85 nir_alu_instr *user = nir_instr_as_alu(nir_src_parent_instr(&src->src));
86 unsigned src_idx = src - user->src;
87 assert(src_idx < nir_op_infos[user->op].num_inputs);
88 unsigned num_comp = nir_ssa_alu_instr_src_components(user, src_idx);
89
90 if (copy->op == nir_op_mov) {
91 def = copy->src[0].src.ssa;
92
93 for (unsigned i = 0; i < num_comp; i++)
94 src->swizzle[i] = copy->src[0].swizzle[src->swizzle[i]];
95 } else {
96 def = copy->src[src->swizzle[0]].src.ssa;
97
98 for (unsigned i = 1; i < num_comp; i++) {
99 if (copy->src[src->swizzle[i]].src.ssa != def)
100 return rewrite_to_vec(user, copy);
101 }
102
103 for (unsigned i = 0; i < num_comp; i++)
104 src->swizzle[i] = copy->src[src->swizzle[i]].swizzle[0];
105 }
106
107 nir_src_rewrite(&src->src, def);
108
109 return true;
110 }
111
112 static bool
copy_propagate(nir_src * src,nir_alu_instr * copy)113 copy_propagate(nir_src *src, nir_alu_instr *copy)
114 {
115 if (!is_swizzleless_move(copy))
116 return false;
117
118 nir_src_rewrite(src, copy->src[0].src.ssa);
119
120 return true;
121 }
122
123 static bool
copy_prop_instr(nir_instr * instr)124 copy_prop_instr(nir_instr *instr)
125 {
126 if (instr->type != nir_instr_type_alu)
127 return false;
128
129 nir_alu_instr *mov = nir_instr_as_alu(instr);
130
131 if (!nir_op_is_vec_or_mov(mov->op))
132 return false;
133
134 bool progress = false;
135
136 nir_foreach_use_including_if_safe(src, &mov->def) {
137 if (!nir_src_is_if(src) && nir_src_parent_instr(src)->type == nir_instr_type_alu)
138 progress |= copy_propagate_alu(container_of(src, nir_alu_src, src), mov);
139 else
140 progress |= copy_propagate(src, mov);
141 }
142
143 if (progress && nir_def_is_unused(&mov->def))
144 nir_instr_remove(&mov->instr);
145
146 return progress;
147 }
148
149 bool
nir_copy_prop_impl(nir_function_impl * impl)150 nir_copy_prop_impl(nir_function_impl *impl)
151 {
152 bool progress = false;
153
154 nir_foreach_block(block, impl) {
155 nir_foreach_instr_safe(instr, block) {
156 progress |= copy_prop_instr(instr);
157 }
158 }
159
160 if (progress) {
161 nir_metadata_preserve(impl, nir_metadata_control_flow);
162 } else {
163 nir_metadata_preserve(impl, nir_metadata_all);
164 }
165
166 return progress;
167 }
168
169 bool
nir_copy_prop(nir_shader * shader)170 nir_copy_prop(nir_shader *shader)
171 {
172 bool progress = false;
173
174 nir_foreach_function_impl(impl, shader) {
175 if (nir_copy_prop_impl(impl))
176 progress = true;
177 }
178
179 return progress;
180 }
181