nir: Add a naieve from-SSA pass
[mesa.git] / src / glsl / nir / nir_from_ssa.c
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 * Jason Ekstrand (jason@jlekstrand.net)
25 *
26 */
27
28 #include "nir.h"
29
30 /*
31 * Implements a quick-and-dirty out-of-ssa pass.
32 */
33
34 struct from_ssa_state {
35 void *mem_ctx;
36 void *dead_ctx;
37 struct hash_table *ssa_table;
38 nir_function_impl *current_impl;
39 };
40
41 static bool
42 rewrite_ssa_src(nir_src *src, void *void_state)
43 {
44 struct from_ssa_state *state = void_state;
45
46 if (src->is_ssa) {
47 struct hash_entry *entry =
48 _mesa_hash_table_search(state->ssa_table, src->ssa);
49 assert(entry);
50 memset(src, 0, sizeof *src);
51 src->reg.reg = (nir_register *)entry->data;
52 }
53
54 return true;
55 }
56
57 static nir_register *
58 reg_create_from_def(nir_ssa_def *def, struct from_ssa_state *state)
59 {
60 nir_register *reg = nir_local_reg_create(state->current_impl);
61 reg->name = def->name;
62 reg->num_components = def->num_components;
63 reg->num_array_elems = 0;
64
65 /* Might as well steal the use-def information from SSA */
66 _mesa_set_destroy(reg->uses, NULL);
67 reg->uses = def->uses;
68 _mesa_set_destroy(reg->if_uses, NULL);
69 reg->if_uses = def->if_uses;
70 _mesa_set_add(reg->defs, _mesa_hash_pointer(def->parent_instr),
71 def->parent_instr);
72
73 /* Add the new register to the table and rewrite the destination */
74 _mesa_hash_table_insert(state->ssa_table, def, reg);
75
76 return reg;
77 }
78
79 static bool
80 rewrite_ssa_dest(nir_dest *dest, void *void_state)
81 {
82 struct from_ssa_state *state = void_state;
83
84 if (dest->is_ssa) {
85 nir_register *reg = reg_create_from_def(&dest->ssa, state);
86 memset(dest, 0, sizeof *dest);
87 dest->reg.reg = reg;
88 }
89
90 return true;
91 }
92
93 static bool
94 convert_from_ssa_block(nir_block *block, void *void_state)
95 {
96 struct from_ssa_state *state = void_state;
97
98 nir_foreach_instr_safe(block, instr) {
99 if (instr->type == nir_instr_type_ssa_undef) {
100 nir_ssa_undef_instr *undef = nir_instr_as_ssa_undef(instr);
101 reg_create_from_def(&undef->def, state);
102 exec_node_remove(&instr->node);
103 ralloc_steal(state->dead_ctx, instr);
104 } else {
105 nir_foreach_src(instr, rewrite_ssa_src, state);
106 nir_foreach_dest(instr, rewrite_ssa_dest, state);
107 }
108 }
109
110 if (block->cf_node.node.next != NULL && /* check that we aren't the end node */
111 !nir_cf_node_is_last(&block->cf_node) &&
112 nir_cf_node_next(&block->cf_node)->type == nir_cf_node_if) {
113 nir_if *if_stmt = nir_cf_node_as_if(nir_cf_node_next(&block->cf_node));
114 rewrite_ssa_src(&if_stmt->condition, state);
115 }
116
117 return true;
118 }
119
120 static bool
121 remove_phi_nodes(nir_block *block, void *void_state)
122 {
123 struct from_ssa_state *state = void_state;
124
125 nir_foreach_instr_safe(block, instr) {
126 /* Phi nodes only ever come at the start of a block */
127 if (instr->type != nir_instr_type_phi)
128 break;
129
130 nir_foreach_dest(instr, rewrite_ssa_dest, state);
131
132 nir_phi_instr *phi = nir_instr_as_phi(instr);
133 foreach_list_typed(nir_phi_src, src, node, &phi->srcs) {
134 assert(src->src.is_ssa);
135 struct hash_entry *entry =
136 _mesa_hash_table_search(state->ssa_table, src->src.ssa);
137 nir_alu_instr *mov = nir_alu_instr_create(state->mem_ctx, nir_op_imov);
138 mov->dest.dest = nir_dest_copy(phi->dest, state->mem_ctx);
139 if (entry) {
140 nir_register *reg = (nir_register *)entry->data;
141 mov->src[0].src.reg.reg = reg;
142 mov->dest.write_mask = (1 << reg->num_components) - 1;
143 } else {
144 mov->src[0].src = nir_src_copy(src->src, state->mem_ctx);
145 mov->dest.write_mask = (1 << src->src.ssa->num_components) - 1;
146 }
147
148 nir_instr *block_end = nir_block_last_instr(src->pred);
149 if (block_end && block_end->type == nir_instr_type_jump) {
150 /* If the last instruction in the block is a jump, we want to
151 * place the moves after the jump. Otherwise, we want to place
152 * them at the very end.
153 */
154 exec_node_insert_node_before(&block_end->node, &mov->instr.node);
155 } else {
156 exec_list_push_tail(&src->pred->instr_list, &mov->instr.node);
157 }
158 }
159
160 exec_node_remove(&instr->node);
161 ralloc_steal(state->dead_ctx, instr);
162 }
163
164 return true;
165 }
166
167 static void
168 nir_convert_from_ssa_impl(nir_function_impl *impl)
169 {
170 struct from_ssa_state state;
171
172 state.mem_ctx = ralloc_parent(impl);
173 state.dead_ctx = ralloc_context(NULL);
174 state.current_impl = impl;
175 state.ssa_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
176 _mesa_key_pointer_equal);
177
178 nir_foreach_block(impl, remove_phi_nodes, &state);
179 nir_foreach_block(impl, convert_from_ssa_block, &state);
180
181 /* Clean up dead instructions and the hash table */
182 ralloc_free(state.dead_ctx);
183 _mesa_hash_table_destroy(state.ssa_table, NULL);
184 }
185
186 void
187 nir_convert_from_ssa(nir_shader *shader)
188 {
189 nir_foreach_overload(shader, overload) {
190 if (overload->impl)
191 nir_convert_from_ssa_impl(overload->impl);
192 }
193 }