1 /*
2 * Copyright 2023 Valve Corporation
3 * Copyright 2014 Intel Corporation
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "nir.h"
8 #include "nir_builder.h"
9 #include "nir_intrinsics.h"
10 #include "nir_intrinsics_indices.h"
11 #include "nir_phi_builder.h"
12 #include "nir_vla.h"
13
14 static bool
should_lower_reg(nir_intrinsic_instr * decl)15 should_lower_reg(nir_intrinsic_instr *decl)
16 {
17 /* This pass only really works on "plain" registers. In particular,
18 * base/indirects are not handled. If it's a packed or array register,
19 * just set the value to NULL so that the rewrite portion of the pass
20 * will know to ignore it.
21 */
22 return nir_intrinsic_num_array_elems(decl) == 0;
23 }
24
25 struct regs_to_ssa_state {
26 nir_builder b;
27
28 /* Scratch bitset for use in setup_reg */
29 unsigned defs_words;
30 BITSET_WORD *defs;
31
32 struct nir_phi_builder *phi_builder;
33 struct nir_phi_builder_value **values;
34 };
35
36 static void
setup_reg(nir_intrinsic_instr * decl,struct regs_to_ssa_state * state)37 setup_reg(nir_intrinsic_instr *decl, struct regs_to_ssa_state *state)
38 {
39 assert(state->values[decl->def.index] == NULL);
40 if (!should_lower_reg(decl))
41 return;
42
43 const unsigned num_components = nir_intrinsic_num_components(decl);
44 const unsigned bit_size = nir_intrinsic_bit_size(decl);
45
46 memset(state->defs, 0, state->defs_words * sizeof(*state->defs));
47
48 nir_foreach_reg_store(store, decl)
49 BITSET_SET(state->defs, nir_src_parent_instr(store)->block->index);
50
51 state->values[decl->def.index] =
52 nir_phi_builder_add_value(state->phi_builder, num_components,
53 bit_size, state->defs);
54 }
55
56 static void
rewrite_load(nir_intrinsic_instr * load,struct regs_to_ssa_state * state)57 rewrite_load(nir_intrinsic_instr *load, struct regs_to_ssa_state *state)
58 {
59 nir_block *block = load->instr.block;
60 nir_def *reg = load->src[0].ssa;
61
62 struct nir_phi_builder_value *value = state->values[reg->index];
63 if (!value)
64 return;
65
66 nir_intrinsic_instr *decl = nir_instr_as_intrinsic(reg->parent_instr);
67 nir_def *def = nir_phi_builder_value_get_block_def(value, block);
68
69 nir_def_rewrite_uses(&load->def, def);
70 nir_instr_remove(&load->instr);
71
72 if (nir_def_is_unused(&decl->def))
73 nir_instr_remove(&decl->instr);
74 }
75
76 static void
rewrite_store(nir_intrinsic_instr * store,struct regs_to_ssa_state * state)77 rewrite_store(nir_intrinsic_instr *store, struct regs_to_ssa_state *state)
78 {
79 nir_block *block = store->instr.block;
80 nir_def *new_value = store->src[0].ssa;
81 nir_def *reg = store->src[1].ssa;
82
83 struct nir_phi_builder_value *value = state->values[reg->index];
84 if (!value)
85 return;
86
87 nir_intrinsic_instr *decl = nir_instr_as_intrinsic(reg->parent_instr);
88 unsigned num_components = nir_intrinsic_num_components(decl);
89 unsigned write_mask = nir_intrinsic_write_mask(store);
90
91 /* Implement write masks by combining together the old/new values */
92 if (write_mask != BITFIELD_MASK(num_components)) {
93 nir_def *old_value =
94 nir_phi_builder_value_get_block_def(value, block);
95
96 nir_def *channels[NIR_MAX_VEC_COMPONENTS] = { NULL };
97 state->b.cursor = nir_before_instr(&store->instr);
98
99 for (unsigned i = 0; i < num_components; ++i) {
100 if (write_mask & BITFIELD_BIT(i))
101 channels[i] = nir_channel(&state->b, new_value, i);
102 else
103 channels[i] = nir_channel(&state->b, old_value, i);
104 }
105
106 new_value = nir_vec(&state->b, channels, num_components);
107 }
108
109 nir_phi_builder_value_set_block_def(value, block, new_value);
110 nir_instr_remove(&store->instr);
111
112 if (nir_def_is_unused(&decl->def))
113 nir_instr_remove(&decl->instr);
114 }
115
116 bool
nir_lower_reg_intrinsics_to_ssa_impl(nir_function_impl * impl)117 nir_lower_reg_intrinsics_to_ssa_impl(nir_function_impl *impl)
118 {
119 bool need_lower_reg = false;
120 nir_foreach_reg_decl(reg, impl) {
121 if (should_lower_reg(reg)) {
122 need_lower_reg = true;
123 break;
124 }
125 }
126 if (!need_lower_reg) {
127 nir_metadata_preserve(impl, nir_metadata_all);
128 return false;
129 }
130
131 nir_metadata_require(impl, nir_metadata_block_index |
132 nir_metadata_dominance);
133 nir_index_ssa_defs(impl);
134
135 void *dead_ctx = ralloc_context(NULL);
136 struct regs_to_ssa_state state;
137 state.b = nir_builder_create(impl);
138 state.defs_words = BITSET_WORDS(impl->num_blocks);
139 state.defs = ralloc_array(dead_ctx, BITSET_WORD, state.defs_words);
140 state.phi_builder = nir_phi_builder_create(state.b.impl);
141 state.values = rzalloc_array(dead_ctx, struct nir_phi_builder_value *,
142 impl->ssa_alloc);
143
144 nir_foreach_block(block, impl) {
145 nir_foreach_instr_safe(instr, block) {
146 if (instr->type != nir_instr_type_intrinsic)
147 continue;
148
149 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
150 switch (intr->intrinsic) {
151 case nir_intrinsic_decl_reg:
152 setup_reg(intr, &state);
153 break;
154 case nir_intrinsic_load_reg:
155 rewrite_load(intr, &state);
156 break;
157 case nir_intrinsic_store_reg:
158 rewrite_store(intr, &state);
159 break;
160 default:
161 break;
162 }
163 }
164 }
165
166 nir_phi_builder_finish(state.phi_builder);
167
168 ralloc_free(dead_ctx);
169
170 nir_metadata_preserve(impl, nir_metadata_block_index |
171 nir_metadata_dominance);
172 return true;
173 }
174
175 bool
nir_lower_reg_intrinsics_to_ssa(nir_shader * shader)176 nir_lower_reg_intrinsics_to_ssa(nir_shader *shader)
177 {
178 bool progress = false;
179
180 nir_foreach_function_impl(impl, shader) {
181 progress |= nir_lower_reg_intrinsics_to_ssa_impl(impl);
182 }
183
184 return progress;
185 }
186