xref: /aosp_15_r20/external/mesa3d/src/compiler/nir/nir_opt_copy_propagate.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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