xref: /aosp_15_r20/external/mesa3d/src/compiler/nir/nir_repair_ssa.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2016 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 
24 #include "nir.h"
25 #include "nir_phi_builder.h"
26 
27 struct repair_ssa_state {
28    nir_function_impl *impl;
29 
30    BITSET_WORD *def_set;
31    struct nir_phi_builder *phi_builder;
32 
33    bool progress;
34 };
35 
36 /* Get ready to build a phi and return the builder */
37 static struct nir_phi_builder *
prep_build_phi(struct repair_ssa_state * state)38 prep_build_phi(struct repair_ssa_state *state)
39 {
40    const unsigned num_words = BITSET_WORDS(state->impl->num_blocks);
41 
42    /* We create the phi builder on-demand. */
43    if (state->phi_builder == NULL) {
44       state->phi_builder = nir_phi_builder_create(state->impl);
45       state->def_set = ralloc_array(NULL, BITSET_WORD, num_words);
46    }
47 
48    /* We're going to build a phi.  That's progress. */
49    state->progress = true;
50 
51    /* Set the defs set to empty */
52    memset(state->def_set, 0, num_words * sizeof(*state->def_set));
53 
54    return state->phi_builder;
55 }
56 
57 static nir_block *
get_src_block(nir_src * src)58 get_src_block(nir_src *src)
59 {
60    if (nir_src_is_if(src)) {
61       return nir_cf_node_as_block(nir_cf_node_prev(&nir_src_parent_if(src)->cf_node));
62    } else if (nir_src_parent_instr(src)->type == nir_instr_type_phi) {
63       return exec_node_data(nir_phi_src, src, src)->pred;
64    } else {
65       return nir_src_parent_instr(src)->block;
66    }
67 }
68 
69 static bool
repair_ssa_def(nir_def * def,void * void_state)70 repair_ssa_def(nir_def *def, void *void_state)
71 {
72    struct repair_ssa_state *state = void_state;
73 
74    bool is_valid = true;
75    nir_foreach_use_including_if(src, def) {
76       nir_block *src_block = get_src_block(src);
77 
78       if (nir_block_is_unreachable(src_block) ||
79           !nir_block_dominates(def->parent_instr->block, src_block)) {
80          is_valid = false;
81          break;
82       }
83    }
84 
85    if (is_valid)
86       return true;
87 
88    struct nir_phi_builder *pb = prep_build_phi(state);
89 
90    BITSET_SET(state->def_set, def->parent_instr->block->index);
91 
92    struct nir_phi_builder_value *val =
93       nir_phi_builder_add_value(pb, def->num_components, def->bit_size,
94                                 state->def_set);
95 
96    nir_phi_builder_value_set_block_def(val, def->parent_instr->block, def);
97 
98    nir_foreach_use_including_if_safe(src, def) {
99       nir_block *block = get_src_block(src);
100 
101       if (block == def->parent_instr->block) {
102          assert(nir_phi_builder_value_get_block_def(val, block) == def);
103          continue;
104       }
105 
106       nir_def *block_def =
107          nir_phi_builder_value_get_block_def(val, block);
108       if (block_def == def)
109          continue;
110 
111       /* If def was a deref and the use we're looking at is a deref that
112        * isn't a cast, we need to wrap it in a cast so we don't loose any
113        * deref information.
114        */
115       if (!nir_src_is_if(src) &&
116           def->parent_instr->type == nir_instr_type_deref &&
117           nir_src_parent_instr(src)->type == nir_instr_type_deref &&
118           nir_instr_as_deref(nir_src_parent_instr(src))->deref_type != nir_deref_type_cast) {
119          nir_deref_instr *cast =
120             nir_deref_instr_create(state->impl->function->shader,
121                                    nir_deref_type_cast);
122 
123          nir_deref_instr *deref = nir_instr_as_deref(def->parent_instr);
124          cast->modes = deref->modes;
125          cast->type = deref->type;
126          cast->parent = nir_src_for_ssa(block_def);
127          cast->cast.ptr_stride = nir_deref_instr_array_stride(deref);
128 
129          nir_def_init(&cast->instr, &cast->def, def->num_components,
130                       def->bit_size);
131          nir_instr_insert(nir_before_instr(nir_src_parent_instr(src)),
132                           &cast->instr);
133          block_def = &cast->def;
134       }
135 
136       if (nir_src_is_if(src))
137          nir_src_rewrite(&nir_src_parent_if(src)->condition, block_def);
138       else
139          nir_src_rewrite(src, block_def);
140    }
141 
142    return true;
143 }
144 
145 bool
nir_repair_ssa_impl(nir_function_impl * impl)146 nir_repair_ssa_impl(nir_function_impl *impl)
147 {
148    struct repair_ssa_state state;
149 
150    state.impl = impl;
151    state.phi_builder = NULL;
152    state.progress = false;
153 
154    nir_metadata_require(impl, nir_metadata_control_flow);
155 
156    nir_foreach_block_unstructured(block, impl) {
157       nir_foreach_instr_safe(instr, block) {
158          nir_foreach_def(instr, repair_ssa_def, &state);
159       }
160    }
161 
162    if (state.progress)
163       nir_metadata_preserve(impl, nir_metadata_control_flow);
164 
165    if (state.phi_builder) {
166       nir_phi_builder_finish(state.phi_builder);
167       ralloc_free(state.def_set);
168    }
169 
170    return state.progress;
171 }
172 
173 /** This pass can be used to repair SSA form in a shader.
174  *
175  * Sometimes a transformation (such as return lowering) will have to make
176  * changes to a shader which, while still correct, break some of NIR's SSA
177  * invariants.  This pass will insert ssa_undefs and phi nodes as needed to
178  * get the shader back into SSA that the validator will like.
179  */
180 bool
nir_repair_ssa(nir_shader * shader)181 nir_repair_ssa(nir_shader *shader)
182 {
183    bool progress = false;
184 
185    nir_foreach_function_impl(impl, shader) {
186       progress = nir_repair_ssa_impl(impl) || progress;
187    }
188 
189    return progress;
190 }
191