1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © Microsoft Corporation
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker *
11*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker * Software.
14*61046927SAndroid Build Coastguard Worker *
15*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*61046927SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*61046927SAndroid Build Coastguard Worker * IN THE SOFTWARE.
22*61046927SAndroid Build Coastguard Worker */
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker #include "dxil_nir.h"
25*61046927SAndroid Build Coastguard Worker #include "dxil_module.h"
26*61046927SAndroid Build Coastguard Worker
27*61046927SAndroid Build Coastguard Worker #include "nir_builder.h"
28*61046927SAndroid Build Coastguard Worker #include "nir_deref.h"
29*61046927SAndroid Build Coastguard Worker #include "nir_worklist.h"
30*61046927SAndroid Build Coastguard Worker #include "nir_to_dxil.h"
31*61046927SAndroid Build Coastguard Worker #include "util/u_math.h"
32*61046927SAndroid Build Coastguard Worker #include "vulkan/vulkan_core.h"
33*61046927SAndroid Build Coastguard Worker
34*61046927SAndroid Build Coastguard Worker static void
cl_type_size_align(const struct glsl_type * type,unsigned * size,unsigned * align)35*61046927SAndroid Build Coastguard Worker cl_type_size_align(const struct glsl_type *type, unsigned *size,
36*61046927SAndroid Build Coastguard Worker unsigned *align)
37*61046927SAndroid Build Coastguard Worker {
38*61046927SAndroid Build Coastguard Worker *size = glsl_get_cl_size(type);
39*61046927SAndroid Build Coastguard Worker *align = glsl_get_cl_alignment(type);
40*61046927SAndroid Build Coastguard Worker }
41*61046927SAndroid Build Coastguard Worker
42*61046927SAndroid Build Coastguard Worker static nir_def *
load_comps_to_vec(nir_builder * b,unsigned src_bit_size,nir_def ** src_comps,unsigned num_src_comps,unsigned dst_bit_size)43*61046927SAndroid Build Coastguard Worker load_comps_to_vec(nir_builder *b, unsigned src_bit_size,
44*61046927SAndroid Build Coastguard Worker nir_def **src_comps, unsigned num_src_comps,
45*61046927SAndroid Build Coastguard Worker unsigned dst_bit_size)
46*61046927SAndroid Build Coastguard Worker {
47*61046927SAndroid Build Coastguard Worker if (src_bit_size == dst_bit_size)
48*61046927SAndroid Build Coastguard Worker return nir_vec(b, src_comps, num_src_comps);
49*61046927SAndroid Build Coastguard Worker else if (src_bit_size > dst_bit_size)
50*61046927SAndroid Build Coastguard Worker return nir_extract_bits(b, src_comps, num_src_comps, 0, src_bit_size * num_src_comps / dst_bit_size, dst_bit_size);
51*61046927SAndroid Build Coastguard Worker
52*61046927SAndroid Build Coastguard Worker unsigned num_dst_comps = DIV_ROUND_UP(num_src_comps * src_bit_size, dst_bit_size);
53*61046927SAndroid Build Coastguard Worker unsigned comps_per_dst = dst_bit_size / src_bit_size;
54*61046927SAndroid Build Coastguard Worker nir_def *dst_comps[4];
55*61046927SAndroid Build Coastguard Worker
56*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_dst_comps; i++) {
57*61046927SAndroid Build Coastguard Worker unsigned src_offs = i * comps_per_dst;
58*61046927SAndroid Build Coastguard Worker
59*61046927SAndroid Build Coastguard Worker dst_comps[i] = nir_u2uN(b, src_comps[src_offs], dst_bit_size);
60*61046927SAndroid Build Coastguard Worker for (unsigned j = 1; j < comps_per_dst && src_offs + j < num_src_comps; j++) {
61*61046927SAndroid Build Coastguard Worker nir_def *tmp = nir_ishl_imm(b, nir_u2uN(b, src_comps[src_offs + j], dst_bit_size),
62*61046927SAndroid Build Coastguard Worker j * src_bit_size);
63*61046927SAndroid Build Coastguard Worker dst_comps[i] = nir_ior(b, dst_comps[i], tmp);
64*61046927SAndroid Build Coastguard Worker }
65*61046927SAndroid Build Coastguard Worker }
66*61046927SAndroid Build Coastguard Worker
67*61046927SAndroid Build Coastguard Worker return nir_vec(b, dst_comps, num_dst_comps);
68*61046927SAndroid Build Coastguard Worker }
69*61046927SAndroid Build Coastguard Worker
70*61046927SAndroid Build Coastguard Worker static bool
lower_32b_offset_load(nir_builder * b,nir_intrinsic_instr * intr,nir_variable * var)71*61046927SAndroid Build Coastguard Worker lower_32b_offset_load(nir_builder *b, nir_intrinsic_instr *intr, nir_variable *var)
72*61046927SAndroid Build Coastguard Worker {
73*61046927SAndroid Build Coastguard Worker unsigned bit_size = intr->def.bit_size;
74*61046927SAndroid Build Coastguard Worker unsigned num_components = intr->def.num_components;
75*61046927SAndroid Build Coastguard Worker unsigned num_bits = num_components * bit_size;
76*61046927SAndroid Build Coastguard Worker
77*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
78*61046927SAndroid Build Coastguard Worker
79*61046927SAndroid Build Coastguard Worker nir_def *offset = intr->src[0].ssa;
80*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_load_shared)
81*61046927SAndroid Build Coastguard Worker offset = nir_iadd_imm(b, offset, nir_intrinsic_base(intr));
82*61046927SAndroid Build Coastguard Worker else
83*61046927SAndroid Build Coastguard Worker offset = nir_u2u32(b, offset);
84*61046927SAndroid Build Coastguard Worker nir_def *index = nir_ushr_imm(b, offset, 2);
85*61046927SAndroid Build Coastguard Worker nir_def *comps[NIR_MAX_VEC_COMPONENTS];
86*61046927SAndroid Build Coastguard Worker nir_def *comps_32bit[NIR_MAX_VEC_COMPONENTS * 2];
87*61046927SAndroid Build Coastguard Worker
88*61046927SAndroid Build Coastguard Worker /* We need to split loads in 32-bit accesses because the buffer
89*61046927SAndroid Build Coastguard Worker * is an i32 array and DXIL does not support type casts.
90*61046927SAndroid Build Coastguard Worker */
91*61046927SAndroid Build Coastguard Worker unsigned num_32bit_comps = DIV_ROUND_UP(num_bits, 32);
92*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_32bit_comps; i++)
93*61046927SAndroid Build Coastguard Worker comps_32bit[i] = nir_load_array_var(b, var, nir_iadd_imm(b, index, i));
94*61046927SAndroid Build Coastguard Worker unsigned num_comps_per_pass = MIN2(num_32bit_comps, 4);
95*61046927SAndroid Build Coastguard Worker
96*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_32bit_comps; i += num_comps_per_pass) {
97*61046927SAndroid Build Coastguard Worker unsigned num_vec32_comps = MIN2(num_32bit_comps - i, 4);
98*61046927SAndroid Build Coastguard Worker unsigned num_dest_comps = num_vec32_comps * 32 / bit_size;
99*61046927SAndroid Build Coastguard Worker nir_def *vec32 = nir_vec(b, &comps_32bit[i], num_vec32_comps);
100*61046927SAndroid Build Coastguard Worker
101*61046927SAndroid Build Coastguard Worker /* If we have 16 bits or less to load we need to adjust the u32 value so
102*61046927SAndroid Build Coastguard Worker * we can always extract the LSB.
103*61046927SAndroid Build Coastguard Worker */
104*61046927SAndroid Build Coastguard Worker if (num_bits <= 16) {
105*61046927SAndroid Build Coastguard Worker nir_def *shift =
106*61046927SAndroid Build Coastguard Worker nir_imul_imm(b, nir_iand_imm(b, offset, 3), 8);
107*61046927SAndroid Build Coastguard Worker vec32 = nir_ushr(b, vec32, shift);
108*61046927SAndroid Build Coastguard Worker }
109*61046927SAndroid Build Coastguard Worker
110*61046927SAndroid Build Coastguard Worker /* And now comes the pack/unpack step to match the original type. */
111*61046927SAndroid Build Coastguard Worker unsigned dest_index = i * 32 / bit_size;
112*61046927SAndroid Build Coastguard Worker nir_def *temp_vec = nir_extract_bits(b, &vec32, 1, 0, num_dest_comps, bit_size);
113*61046927SAndroid Build Coastguard Worker for (unsigned comp = 0; comp < num_dest_comps; ++comp, ++dest_index)
114*61046927SAndroid Build Coastguard Worker comps[dest_index] = nir_channel(b, temp_vec, comp);
115*61046927SAndroid Build Coastguard Worker }
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Worker nir_def *result = nir_vec(b, comps, num_components);
118*61046927SAndroid Build Coastguard Worker nir_def_replace(&intr->def, result);
119*61046927SAndroid Build Coastguard Worker
120*61046927SAndroid Build Coastguard Worker return true;
121*61046927SAndroid Build Coastguard Worker }
122*61046927SAndroid Build Coastguard Worker
123*61046927SAndroid Build Coastguard Worker static void
lower_masked_store_vec32(nir_builder * b,nir_def * offset,nir_def * index,nir_def * vec32,unsigned num_bits,nir_variable * var,unsigned alignment)124*61046927SAndroid Build Coastguard Worker lower_masked_store_vec32(nir_builder *b, nir_def *offset, nir_def *index,
125*61046927SAndroid Build Coastguard Worker nir_def *vec32, unsigned num_bits, nir_variable *var, unsigned alignment)
126*61046927SAndroid Build Coastguard Worker {
127*61046927SAndroid Build Coastguard Worker nir_def *mask = nir_imm_int(b, (1 << num_bits) - 1);
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker /* If we have small alignments, we need to place them correctly in the u32 component. */
130*61046927SAndroid Build Coastguard Worker if (alignment <= 2) {
131*61046927SAndroid Build Coastguard Worker nir_def *shift =
132*61046927SAndroid Build Coastguard Worker nir_imul_imm(b, nir_iand_imm(b, offset, 3), 8);
133*61046927SAndroid Build Coastguard Worker
134*61046927SAndroid Build Coastguard Worker vec32 = nir_ishl(b, vec32, shift);
135*61046927SAndroid Build Coastguard Worker mask = nir_ishl(b, mask, shift);
136*61046927SAndroid Build Coastguard Worker }
137*61046927SAndroid Build Coastguard Worker
138*61046927SAndroid Build Coastguard Worker if (var->data.mode == nir_var_mem_shared) {
139*61046927SAndroid Build Coastguard Worker /* Use the dedicated masked intrinsic */
140*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_build_deref_array(b, nir_build_deref_var(b, var), index);
141*61046927SAndroid Build Coastguard Worker nir_deref_atomic(b, 32, &deref->def, nir_inot(b, mask), .atomic_op = nir_atomic_op_iand);
142*61046927SAndroid Build Coastguard Worker nir_deref_atomic(b, 32, &deref->def, vec32, .atomic_op = nir_atomic_op_ior);
143*61046927SAndroid Build Coastguard Worker } else {
144*61046927SAndroid Build Coastguard Worker /* For scratch, since we don't need atomics, just generate the read-modify-write in NIR */
145*61046927SAndroid Build Coastguard Worker nir_def *load = nir_load_array_var(b, var, index);
146*61046927SAndroid Build Coastguard Worker
147*61046927SAndroid Build Coastguard Worker nir_def *new_val = nir_ior(b, vec32,
148*61046927SAndroid Build Coastguard Worker nir_iand(b,
149*61046927SAndroid Build Coastguard Worker nir_inot(b, mask),
150*61046927SAndroid Build Coastguard Worker load));
151*61046927SAndroid Build Coastguard Worker
152*61046927SAndroid Build Coastguard Worker nir_store_array_var(b, var, index, new_val, 1);
153*61046927SAndroid Build Coastguard Worker }
154*61046927SAndroid Build Coastguard Worker }
155*61046927SAndroid Build Coastguard Worker
156*61046927SAndroid Build Coastguard Worker static bool
lower_32b_offset_store(nir_builder * b,nir_intrinsic_instr * intr,nir_variable * var)157*61046927SAndroid Build Coastguard Worker lower_32b_offset_store(nir_builder *b, nir_intrinsic_instr *intr, nir_variable *var)
158*61046927SAndroid Build Coastguard Worker {
159*61046927SAndroid Build Coastguard Worker unsigned num_components = nir_src_num_components(intr->src[0]);
160*61046927SAndroid Build Coastguard Worker unsigned bit_size = nir_src_bit_size(intr->src[0]);
161*61046927SAndroid Build Coastguard Worker unsigned num_bits = num_components * bit_size;
162*61046927SAndroid Build Coastguard Worker
163*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
164*61046927SAndroid Build Coastguard Worker
165*61046927SAndroid Build Coastguard Worker nir_def *offset = intr->src[1].ssa;
166*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_store_shared)
167*61046927SAndroid Build Coastguard Worker offset = nir_iadd_imm(b, offset, nir_intrinsic_base(intr));
168*61046927SAndroid Build Coastguard Worker else
169*61046927SAndroid Build Coastguard Worker offset = nir_u2u32(b, offset);
170*61046927SAndroid Build Coastguard Worker nir_def *comps[NIR_MAX_VEC_COMPONENTS];
171*61046927SAndroid Build Coastguard Worker
172*61046927SAndroid Build Coastguard Worker unsigned comp_idx = 0;
173*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_components; i++)
174*61046927SAndroid Build Coastguard Worker comps[i] = nir_channel(b, intr->src[0].ssa, i);
175*61046927SAndroid Build Coastguard Worker
176*61046927SAndroid Build Coastguard Worker unsigned step = MAX2(bit_size, 32);
177*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_bits; i += step) {
178*61046927SAndroid Build Coastguard Worker /* For each 4byte chunk (or smaller) we generate a 32bit scalar store. */
179*61046927SAndroid Build Coastguard Worker unsigned substore_num_bits = MIN2(num_bits - i, step);
180*61046927SAndroid Build Coastguard Worker nir_def *local_offset = nir_iadd_imm(b, offset, i / 8);
181*61046927SAndroid Build Coastguard Worker nir_def *vec32 = load_comps_to_vec(b, bit_size, &comps[comp_idx],
182*61046927SAndroid Build Coastguard Worker substore_num_bits / bit_size, 32);
183*61046927SAndroid Build Coastguard Worker nir_def *index = nir_ushr_imm(b, local_offset, 2);
184*61046927SAndroid Build Coastguard Worker
185*61046927SAndroid Build Coastguard Worker /* For anything less than 32bits we need to use the masked version of the
186*61046927SAndroid Build Coastguard Worker * intrinsic to preserve data living in the same 32bit slot. */
187*61046927SAndroid Build Coastguard Worker if (substore_num_bits < 32) {
188*61046927SAndroid Build Coastguard Worker lower_masked_store_vec32(b, local_offset, index, vec32, num_bits, var, nir_intrinsic_align(intr));
189*61046927SAndroid Build Coastguard Worker } else {
190*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < vec32->num_components; ++i)
191*61046927SAndroid Build Coastguard Worker nir_store_array_var(b, var, nir_iadd_imm(b, index, i), nir_channel(b, vec32, i), 1);
192*61046927SAndroid Build Coastguard Worker }
193*61046927SAndroid Build Coastguard Worker
194*61046927SAndroid Build Coastguard Worker comp_idx += substore_num_bits / bit_size;
195*61046927SAndroid Build Coastguard Worker }
196*61046927SAndroid Build Coastguard Worker
197*61046927SAndroid Build Coastguard Worker nir_instr_remove(&intr->instr);
198*61046927SAndroid Build Coastguard Worker
199*61046927SAndroid Build Coastguard Worker return true;
200*61046927SAndroid Build Coastguard Worker }
201*61046927SAndroid Build Coastguard Worker
202*61046927SAndroid Build Coastguard Worker #define CONSTANT_LOCATION_UNVISITED 0
203*61046927SAndroid Build Coastguard Worker #define CONSTANT_LOCATION_VALID 1
204*61046927SAndroid Build Coastguard Worker #define CONSTANT_LOCATION_INVALID 2
205*61046927SAndroid Build Coastguard Worker
206*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_constant_to_temp(nir_shader * nir)207*61046927SAndroid Build Coastguard Worker dxil_nir_lower_constant_to_temp(nir_shader *nir)
208*61046927SAndroid Build Coastguard Worker {
209*61046927SAndroid Build Coastguard Worker bool progress = false;
210*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, nir, nir_var_mem_constant)
211*61046927SAndroid Build Coastguard Worker var->data.location = var->constant_initializer ?
212*61046927SAndroid Build Coastguard Worker CONSTANT_LOCATION_UNVISITED : CONSTANT_LOCATION_INVALID;
213*61046927SAndroid Build Coastguard Worker
214*61046927SAndroid Build Coastguard Worker /* First pass: collect all UBO accesses that could be turned into
215*61046927SAndroid Build Coastguard Worker * shader temp accesses.
216*61046927SAndroid Build Coastguard Worker */
217*61046927SAndroid Build Coastguard Worker nir_foreach_function(func, nir) {
218*61046927SAndroid Build Coastguard Worker if (!func->is_entrypoint)
219*61046927SAndroid Build Coastguard Worker continue;
220*61046927SAndroid Build Coastguard Worker assert(func->impl);
221*61046927SAndroid Build Coastguard Worker
222*61046927SAndroid Build Coastguard Worker nir_foreach_block(block, func->impl) {
223*61046927SAndroid Build Coastguard Worker nir_foreach_instr_safe(instr, block) {
224*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_deref)
225*61046927SAndroid Build Coastguard Worker continue;
226*61046927SAndroid Build Coastguard Worker
227*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_instr_as_deref(instr);
228*61046927SAndroid Build Coastguard Worker if (!nir_deref_mode_is(deref, nir_var_mem_constant) ||
229*61046927SAndroid Build Coastguard Worker deref->deref_type != nir_deref_type_var ||
230*61046927SAndroid Build Coastguard Worker deref->var->data.location == CONSTANT_LOCATION_INVALID)
231*61046927SAndroid Build Coastguard Worker continue;
232*61046927SAndroid Build Coastguard Worker
233*61046927SAndroid Build Coastguard Worker deref->var->data.location = nir_deref_instr_has_complex_use(deref, 0) ?
234*61046927SAndroid Build Coastguard Worker CONSTANT_LOCATION_INVALID : CONSTANT_LOCATION_VALID;
235*61046927SAndroid Build Coastguard Worker }
236*61046927SAndroid Build Coastguard Worker }
237*61046927SAndroid Build Coastguard Worker }
238*61046927SAndroid Build Coastguard Worker
239*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, nir, nir_var_mem_constant) {
240*61046927SAndroid Build Coastguard Worker if (var->data.location != CONSTANT_LOCATION_VALID)
241*61046927SAndroid Build Coastguard Worker continue;
242*61046927SAndroid Build Coastguard Worker
243*61046927SAndroid Build Coastguard Worker /* Change the variable mode. */
244*61046927SAndroid Build Coastguard Worker var->data.mode = nir_var_shader_temp;
245*61046927SAndroid Build Coastguard Worker
246*61046927SAndroid Build Coastguard Worker progress = true;
247*61046927SAndroid Build Coastguard Worker }
248*61046927SAndroid Build Coastguard Worker
249*61046927SAndroid Build Coastguard Worker /* Second pass: patch all derefs that were accessing the converted UBOs
250*61046927SAndroid Build Coastguard Worker * variables.
251*61046927SAndroid Build Coastguard Worker */
252*61046927SAndroid Build Coastguard Worker nir_foreach_function(func, nir) {
253*61046927SAndroid Build Coastguard Worker if (!func->is_entrypoint)
254*61046927SAndroid Build Coastguard Worker continue;
255*61046927SAndroid Build Coastguard Worker assert(func->impl);
256*61046927SAndroid Build Coastguard Worker
257*61046927SAndroid Build Coastguard Worker nir_builder b = nir_builder_create(func->impl);
258*61046927SAndroid Build Coastguard Worker nir_foreach_block(block, func->impl) {
259*61046927SAndroid Build Coastguard Worker nir_foreach_instr_safe(instr, block) {
260*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_deref)
261*61046927SAndroid Build Coastguard Worker continue;
262*61046927SAndroid Build Coastguard Worker
263*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_instr_as_deref(instr);
264*61046927SAndroid Build Coastguard Worker if (nir_deref_mode_is(deref, nir_var_mem_constant)) {
265*61046927SAndroid Build Coastguard Worker nir_deref_instr *parent = deref;
266*61046927SAndroid Build Coastguard Worker while (parent && parent->deref_type != nir_deref_type_var)
267*61046927SAndroid Build Coastguard Worker parent = nir_src_as_deref(parent->parent);
268*61046927SAndroid Build Coastguard Worker if (parent && parent->var->data.mode != nir_var_mem_constant) {
269*61046927SAndroid Build Coastguard Worker deref->modes = parent->var->data.mode;
270*61046927SAndroid Build Coastguard Worker /* Also change "pointer" size to 32-bit since this is now a logical pointer */
271*61046927SAndroid Build Coastguard Worker deref->def.bit_size = 32;
272*61046927SAndroid Build Coastguard Worker if (deref->deref_type == nir_deref_type_array) {
273*61046927SAndroid Build Coastguard Worker b.cursor = nir_before_instr(instr);
274*61046927SAndroid Build Coastguard Worker nir_src_rewrite(&deref->arr.index, nir_u2u32(&b, deref->arr.index.ssa));
275*61046927SAndroid Build Coastguard Worker }
276*61046927SAndroid Build Coastguard Worker }
277*61046927SAndroid Build Coastguard Worker }
278*61046927SAndroid Build Coastguard Worker }
279*61046927SAndroid Build Coastguard Worker }
280*61046927SAndroid Build Coastguard Worker }
281*61046927SAndroid Build Coastguard Worker
282*61046927SAndroid Build Coastguard Worker return progress;
283*61046927SAndroid Build Coastguard Worker }
284*61046927SAndroid Build Coastguard Worker
285*61046927SAndroid Build Coastguard Worker static bool
flatten_var_arrays(nir_builder * b,nir_intrinsic_instr * intr,void * data)286*61046927SAndroid Build Coastguard Worker flatten_var_arrays(nir_builder *b, nir_intrinsic_instr *intr, void *data)
287*61046927SAndroid Build Coastguard Worker {
288*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
289*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_deref:
290*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_deref:
291*61046927SAndroid Build Coastguard Worker case nir_intrinsic_deref_atomic:
292*61046927SAndroid Build Coastguard Worker case nir_intrinsic_deref_atomic_swap:
293*61046927SAndroid Build Coastguard Worker break;
294*61046927SAndroid Build Coastguard Worker default:
295*61046927SAndroid Build Coastguard Worker return false;
296*61046927SAndroid Build Coastguard Worker }
297*61046927SAndroid Build Coastguard Worker
298*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
299*61046927SAndroid Build Coastguard Worker nir_variable *var = NULL;
300*61046927SAndroid Build Coastguard Worker for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
301*61046927SAndroid Build Coastguard Worker if (d->deref_type == nir_deref_type_cast)
302*61046927SAndroid Build Coastguard Worker return false;
303*61046927SAndroid Build Coastguard Worker if (d->deref_type == nir_deref_type_var) {
304*61046927SAndroid Build Coastguard Worker var = d->var;
305*61046927SAndroid Build Coastguard Worker if (d->type == var->type)
306*61046927SAndroid Build Coastguard Worker return false;
307*61046927SAndroid Build Coastguard Worker }
308*61046927SAndroid Build Coastguard Worker }
309*61046927SAndroid Build Coastguard Worker if (!var)
310*61046927SAndroid Build Coastguard Worker return false;
311*61046927SAndroid Build Coastguard Worker
312*61046927SAndroid Build Coastguard Worker nir_deref_path path;
313*61046927SAndroid Build Coastguard Worker nir_deref_path_init(&path, deref, NULL);
314*61046927SAndroid Build Coastguard Worker
315*61046927SAndroid Build Coastguard Worker assert(path.path[0]->deref_type == nir_deref_type_var);
316*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&path.path[0]->instr);
317*61046927SAndroid Build Coastguard Worker nir_deref_instr *new_var_deref = nir_build_deref_var(b, var);
318*61046927SAndroid Build Coastguard Worker nir_def *index = NULL;
319*61046927SAndroid Build Coastguard Worker for (unsigned level = 1; path.path[level]; ++level) {
320*61046927SAndroid Build Coastguard Worker nir_deref_instr *arr_deref = path.path[level];
321*61046927SAndroid Build Coastguard Worker assert(arr_deref->deref_type == nir_deref_type_array);
322*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&arr_deref->instr);
323*61046927SAndroid Build Coastguard Worker nir_def *val = nir_imul_imm(b, arr_deref->arr.index.ssa,
324*61046927SAndroid Build Coastguard Worker glsl_get_component_slots(arr_deref->type));
325*61046927SAndroid Build Coastguard Worker if (index) {
326*61046927SAndroid Build Coastguard Worker index = nir_iadd(b, index, val);
327*61046927SAndroid Build Coastguard Worker } else {
328*61046927SAndroid Build Coastguard Worker index = val;
329*61046927SAndroid Build Coastguard Worker }
330*61046927SAndroid Build Coastguard Worker }
331*61046927SAndroid Build Coastguard Worker
332*61046927SAndroid Build Coastguard Worker unsigned vector_comps = intr->num_components;
333*61046927SAndroid Build Coastguard Worker if (vector_comps > 1) {
334*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
335*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_load_deref) {
336*61046927SAndroid Build Coastguard Worker nir_def *components[NIR_MAX_VEC_COMPONENTS];
337*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < vector_comps; ++i) {
338*61046927SAndroid Build Coastguard Worker nir_def *final_index = index ? nir_iadd_imm(b, index, i) : nir_imm_int(b, i);
339*61046927SAndroid Build Coastguard Worker nir_deref_instr *comp_deref = nir_build_deref_array(b, new_var_deref, final_index);
340*61046927SAndroid Build Coastguard Worker components[i] = nir_load_deref(b, comp_deref);
341*61046927SAndroid Build Coastguard Worker }
342*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&intr->def, nir_vec(b, components, vector_comps));
343*61046927SAndroid Build Coastguard Worker } else if (intr->intrinsic == nir_intrinsic_store_deref) {
344*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < vector_comps; ++i) {
345*61046927SAndroid Build Coastguard Worker if (((1 << i) & nir_intrinsic_write_mask(intr)) == 0)
346*61046927SAndroid Build Coastguard Worker continue;
347*61046927SAndroid Build Coastguard Worker nir_def *final_index = index ? nir_iadd_imm(b, index, i) : nir_imm_int(b, i);
348*61046927SAndroid Build Coastguard Worker nir_deref_instr *comp_deref = nir_build_deref_array(b, new_var_deref, final_index);
349*61046927SAndroid Build Coastguard Worker nir_store_deref(b, comp_deref, nir_channel(b, intr->src[1].ssa, i), 1);
350*61046927SAndroid Build Coastguard Worker }
351*61046927SAndroid Build Coastguard Worker }
352*61046927SAndroid Build Coastguard Worker nir_instr_remove(&intr->instr);
353*61046927SAndroid Build Coastguard Worker } else {
354*61046927SAndroid Build Coastguard Worker nir_src_rewrite(&intr->src[0], &nir_build_deref_array(b, new_var_deref, index)->def);
355*61046927SAndroid Build Coastguard Worker }
356*61046927SAndroid Build Coastguard Worker
357*61046927SAndroid Build Coastguard Worker nir_deref_path_finish(&path);
358*61046927SAndroid Build Coastguard Worker return true;
359*61046927SAndroid Build Coastguard Worker }
360*61046927SAndroid Build Coastguard Worker
361*61046927SAndroid Build Coastguard Worker static void
flatten_constant_initializer(nir_variable * var,nir_constant * src,nir_constant *** dest,unsigned vector_elements)362*61046927SAndroid Build Coastguard Worker flatten_constant_initializer(nir_variable *var, nir_constant *src, nir_constant ***dest, unsigned vector_elements)
363*61046927SAndroid Build Coastguard Worker {
364*61046927SAndroid Build Coastguard Worker if (src->num_elements == 0) {
365*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < vector_elements; ++i) {
366*61046927SAndroid Build Coastguard Worker nir_constant *new_scalar = rzalloc(var, nir_constant);
367*61046927SAndroid Build Coastguard Worker memcpy(&new_scalar->values[0], &src->values[i], sizeof(src->values[0]));
368*61046927SAndroid Build Coastguard Worker new_scalar->is_null_constant = src->values[i].u64 == 0;
369*61046927SAndroid Build Coastguard Worker
370*61046927SAndroid Build Coastguard Worker nir_constant **array_entry = (*dest)++;
371*61046927SAndroid Build Coastguard Worker *array_entry = new_scalar;
372*61046927SAndroid Build Coastguard Worker }
373*61046927SAndroid Build Coastguard Worker } else {
374*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < src->num_elements; ++i)
375*61046927SAndroid Build Coastguard Worker flatten_constant_initializer(var, src->elements[i], dest, vector_elements);
376*61046927SAndroid Build Coastguard Worker }
377*61046927SAndroid Build Coastguard Worker }
378*61046927SAndroid Build Coastguard Worker
379*61046927SAndroid Build Coastguard Worker static bool
flatten_var_array_types(nir_variable * var)380*61046927SAndroid Build Coastguard Worker flatten_var_array_types(nir_variable *var)
381*61046927SAndroid Build Coastguard Worker {
382*61046927SAndroid Build Coastguard Worker assert(!glsl_type_is_struct(glsl_without_array(var->type)));
383*61046927SAndroid Build Coastguard Worker const struct glsl_type *matrix_type = glsl_without_array(var->type);
384*61046927SAndroid Build Coastguard Worker if (!glsl_type_is_array_of_arrays(var->type) && glsl_get_components(matrix_type) == 1)
385*61046927SAndroid Build Coastguard Worker return false;
386*61046927SAndroid Build Coastguard Worker
387*61046927SAndroid Build Coastguard Worker enum glsl_base_type base_type = glsl_get_base_type(matrix_type);
388*61046927SAndroid Build Coastguard Worker const struct glsl_type *flattened_type = glsl_array_type(glsl_scalar_type(base_type),
389*61046927SAndroid Build Coastguard Worker glsl_get_component_slots(var->type), 0);
390*61046927SAndroid Build Coastguard Worker var->type = flattened_type;
391*61046927SAndroid Build Coastguard Worker if (var->constant_initializer) {
392*61046927SAndroid Build Coastguard Worker nir_constant **new_elements = ralloc_array(var, nir_constant *, glsl_get_length(flattened_type));
393*61046927SAndroid Build Coastguard Worker nir_constant **temp = new_elements;
394*61046927SAndroid Build Coastguard Worker flatten_constant_initializer(var, var->constant_initializer, &temp, glsl_get_vector_elements(matrix_type));
395*61046927SAndroid Build Coastguard Worker var->constant_initializer->num_elements = glsl_get_length(flattened_type);
396*61046927SAndroid Build Coastguard Worker var->constant_initializer->elements = new_elements;
397*61046927SAndroid Build Coastguard Worker }
398*61046927SAndroid Build Coastguard Worker return true;
399*61046927SAndroid Build Coastguard Worker }
400*61046927SAndroid Build Coastguard Worker
401*61046927SAndroid Build Coastguard Worker bool
dxil_nir_flatten_var_arrays(nir_shader * shader,nir_variable_mode modes)402*61046927SAndroid Build Coastguard Worker dxil_nir_flatten_var_arrays(nir_shader *shader, nir_variable_mode modes)
403*61046927SAndroid Build Coastguard Worker {
404*61046927SAndroid Build Coastguard Worker bool progress = false;
405*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, shader, modes & ~nir_var_function_temp)
406*61046927SAndroid Build Coastguard Worker progress |= flatten_var_array_types(var);
407*61046927SAndroid Build Coastguard Worker
408*61046927SAndroid Build Coastguard Worker if (modes & nir_var_function_temp) {
409*61046927SAndroid Build Coastguard Worker nir_foreach_function_impl(impl, shader) {
410*61046927SAndroid Build Coastguard Worker nir_foreach_function_temp_variable(var, impl)
411*61046927SAndroid Build Coastguard Worker progress |= flatten_var_array_types(var);
412*61046927SAndroid Build Coastguard Worker }
413*61046927SAndroid Build Coastguard Worker }
414*61046927SAndroid Build Coastguard Worker
415*61046927SAndroid Build Coastguard Worker if (!progress)
416*61046927SAndroid Build Coastguard Worker return false;
417*61046927SAndroid Build Coastguard Worker
418*61046927SAndroid Build Coastguard Worker nir_shader_intrinsics_pass(shader, flatten_var_arrays,
419*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow |
420*61046927SAndroid Build Coastguard Worker nir_metadata_loop_analysis,
421*61046927SAndroid Build Coastguard Worker NULL);
422*61046927SAndroid Build Coastguard Worker nir_remove_dead_derefs(shader);
423*61046927SAndroid Build Coastguard Worker return true;
424*61046927SAndroid Build Coastguard Worker }
425*61046927SAndroid Build Coastguard Worker
426*61046927SAndroid Build Coastguard Worker static bool
lower_deref_bit_size(nir_builder * b,nir_intrinsic_instr * intr,void * data)427*61046927SAndroid Build Coastguard Worker lower_deref_bit_size(nir_builder *b, nir_intrinsic_instr *intr, void *data)
428*61046927SAndroid Build Coastguard Worker {
429*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
430*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_deref:
431*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_deref:
432*61046927SAndroid Build Coastguard Worker break;
433*61046927SAndroid Build Coastguard Worker default:
434*61046927SAndroid Build Coastguard Worker /* Atomics can't be smaller than 32-bit */
435*61046927SAndroid Build Coastguard Worker return false;
436*61046927SAndroid Build Coastguard Worker }
437*61046927SAndroid Build Coastguard Worker
438*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
439*61046927SAndroid Build Coastguard Worker nir_variable *var = nir_deref_instr_get_variable(deref);
440*61046927SAndroid Build Coastguard Worker /* Only interested in full deref chains */
441*61046927SAndroid Build Coastguard Worker if (!var)
442*61046927SAndroid Build Coastguard Worker return false;
443*61046927SAndroid Build Coastguard Worker
444*61046927SAndroid Build Coastguard Worker const struct glsl_type *var_scalar_type = glsl_without_array(var->type);
445*61046927SAndroid Build Coastguard Worker if (deref->type == var_scalar_type || !glsl_type_is_scalar(var_scalar_type))
446*61046927SAndroid Build Coastguard Worker return false;
447*61046927SAndroid Build Coastguard Worker
448*61046927SAndroid Build Coastguard Worker assert(deref->deref_type == nir_deref_type_var || deref->deref_type == nir_deref_type_array);
449*61046927SAndroid Build Coastguard Worker const struct glsl_type *old_glsl_type = deref->type;
450*61046927SAndroid Build Coastguard Worker nir_alu_type old_type = nir_get_nir_type_for_glsl_type(old_glsl_type);
451*61046927SAndroid Build Coastguard Worker nir_alu_type new_type = nir_get_nir_type_for_glsl_type(var_scalar_type);
452*61046927SAndroid Build Coastguard Worker if (glsl_get_bit_size(old_glsl_type) < glsl_get_bit_size(var_scalar_type)) {
453*61046927SAndroid Build Coastguard Worker deref->type = var_scalar_type;
454*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_load_deref) {
455*61046927SAndroid Build Coastguard Worker intr->def.bit_size = glsl_get_bit_size(var_scalar_type);
456*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(&intr->instr);
457*61046927SAndroid Build Coastguard Worker nir_def *downcast = nir_type_convert(b, &intr->def, new_type, old_type, nir_rounding_mode_undef);
458*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses_after(&intr->def, downcast, downcast->parent_instr);
459*61046927SAndroid Build Coastguard Worker }
460*61046927SAndroid Build Coastguard Worker else {
461*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
462*61046927SAndroid Build Coastguard Worker nir_def *upcast = nir_type_convert(b, intr->src[1].ssa, old_type, new_type, nir_rounding_mode_undef);
463*61046927SAndroid Build Coastguard Worker nir_src_rewrite(&intr->src[1], upcast);
464*61046927SAndroid Build Coastguard Worker }
465*61046927SAndroid Build Coastguard Worker
466*61046927SAndroid Build Coastguard Worker while (deref->deref_type == nir_deref_type_array) {
467*61046927SAndroid Build Coastguard Worker nir_deref_instr *parent = nir_deref_instr_parent(deref);
468*61046927SAndroid Build Coastguard Worker parent->type = glsl_type_wrap_in_arrays(deref->type, parent->type);
469*61046927SAndroid Build Coastguard Worker deref = parent;
470*61046927SAndroid Build Coastguard Worker }
471*61046927SAndroid Build Coastguard Worker } else {
472*61046927SAndroid Build Coastguard Worker /* Assumed arrays are already flattened */
473*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&deref->instr);
474*61046927SAndroid Build Coastguard Worker nir_deref_instr *parent = nir_build_deref_var(b, var);
475*61046927SAndroid Build Coastguard Worker if (deref->deref_type == nir_deref_type_array)
476*61046927SAndroid Build Coastguard Worker deref = nir_build_deref_array(b, parent, nir_imul_imm(b, deref->arr.index.ssa, 2));
477*61046927SAndroid Build Coastguard Worker else
478*61046927SAndroid Build Coastguard Worker deref = nir_build_deref_array_imm(b, parent, 0);
479*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref2 = nir_build_deref_array(b, parent,
480*61046927SAndroid Build Coastguard Worker nir_iadd_imm(b, deref->arr.index.ssa, 1));
481*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
482*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_load_deref) {
483*61046927SAndroid Build Coastguard Worker nir_def *src1 = nir_load_deref(b, deref);
484*61046927SAndroid Build Coastguard Worker nir_def *src2 = nir_load_deref(b, deref2);
485*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&intr->def, nir_pack_64_2x32_split(b, src1, src2));
486*61046927SAndroid Build Coastguard Worker } else {
487*61046927SAndroid Build Coastguard Worker nir_def *src1 = nir_unpack_64_2x32_split_x(b, intr->src[1].ssa);
488*61046927SAndroid Build Coastguard Worker nir_def *src2 = nir_unpack_64_2x32_split_y(b, intr->src[1].ssa);
489*61046927SAndroid Build Coastguard Worker nir_store_deref(b, deref, src1, 1);
490*61046927SAndroid Build Coastguard Worker nir_store_deref(b, deref, src2, 1);
491*61046927SAndroid Build Coastguard Worker }
492*61046927SAndroid Build Coastguard Worker nir_instr_remove(&intr->instr);
493*61046927SAndroid Build Coastguard Worker }
494*61046927SAndroid Build Coastguard Worker return true;
495*61046927SAndroid Build Coastguard Worker }
496*61046927SAndroid Build Coastguard Worker
497*61046927SAndroid Build Coastguard Worker static bool
lower_var_bit_size_types(nir_variable * var,unsigned min_bit_size,unsigned max_bit_size)498*61046927SAndroid Build Coastguard Worker lower_var_bit_size_types(nir_variable *var, unsigned min_bit_size, unsigned max_bit_size)
499*61046927SAndroid Build Coastguard Worker {
500*61046927SAndroid Build Coastguard Worker assert(!glsl_type_is_array_of_arrays(var->type) && !glsl_type_is_struct(var->type));
501*61046927SAndroid Build Coastguard Worker const struct glsl_type *type = glsl_without_array(var->type);
502*61046927SAndroid Build Coastguard Worker assert(glsl_type_is_scalar(type));
503*61046927SAndroid Build Coastguard Worker enum glsl_base_type base_type = glsl_get_base_type(type);
504*61046927SAndroid Build Coastguard Worker if (glsl_base_type_get_bit_size(base_type) < min_bit_size) {
505*61046927SAndroid Build Coastguard Worker switch (min_bit_size) {
506*61046927SAndroid Build Coastguard Worker case 16:
507*61046927SAndroid Build Coastguard Worker switch (base_type) {
508*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_BOOL:
509*61046927SAndroid Build Coastguard Worker base_type = GLSL_TYPE_UINT16;
510*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < (var->constant_initializer ? var->constant_initializer->num_elements : 0); ++i)
511*61046927SAndroid Build Coastguard Worker var->constant_initializer->elements[i]->values[0].u16 = var->constant_initializer->elements[i]->values[0].b ? 0xffff : 0;
512*61046927SAndroid Build Coastguard Worker break;
513*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_INT8:
514*61046927SAndroid Build Coastguard Worker base_type = GLSL_TYPE_INT16;
515*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < (var->constant_initializer ? var->constant_initializer->num_elements : 0); ++i)
516*61046927SAndroid Build Coastguard Worker var->constant_initializer->elements[i]->values[0].i16 = var->constant_initializer->elements[i]->values[0].i8;
517*61046927SAndroid Build Coastguard Worker break;
518*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_UINT8: base_type = GLSL_TYPE_UINT16; break;
519*61046927SAndroid Build Coastguard Worker default: unreachable("Unexpected base type");
520*61046927SAndroid Build Coastguard Worker }
521*61046927SAndroid Build Coastguard Worker break;
522*61046927SAndroid Build Coastguard Worker case 32:
523*61046927SAndroid Build Coastguard Worker switch (base_type) {
524*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_BOOL:
525*61046927SAndroid Build Coastguard Worker base_type = GLSL_TYPE_UINT;
526*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < (var->constant_initializer ? var->constant_initializer->num_elements : 0); ++i)
527*61046927SAndroid Build Coastguard Worker var->constant_initializer->elements[i]->values[0].u32 = var->constant_initializer->elements[i]->values[0].b ? 0xffffffff : 0;
528*61046927SAndroid Build Coastguard Worker break;
529*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_INT8:
530*61046927SAndroid Build Coastguard Worker base_type = GLSL_TYPE_INT;
531*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < (var->constant_initializer ? var->constant_initializer->num_elements : 0); ++i)
532*61046927SAndroid Build Coastguard Worker var->constant_initializer->elements[i]->values[0].i32 = var->constant_initializer->elements[i]->values[0].i8;
533*61046927SAndroid Build Coastguard Worker break;
534*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_INT16:
535*61046927SAndroid Build Coastguard Worker base_type = GLSL_TYPE_INT;
536*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < (var->constant_initializer ? var->constant_initializer->num_elements : 0); ++i)
537*61046927SAndroid Build Coastguard Worker var->constant_initializer->elements[i]->values[0].i32 = var->constant_initializer->elements[i]->values[0].i16;
538*61046927SAndroid Build Coastguard Worker break;
539*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_FLOAT16:
540*61046927SAndroid Build Coastguard Worker base_type = GLSL_TYPE_FLOAT;
541*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < (var->constant_initializer ? var->constant_initializer->num_elements : 0); ++i)
542*61046927SAndroid Build Coastguard Worker var->constant_initializer->elements[i]->values[0].f32 = _mesa_half_to_float(var->constant_initializer->elements[i]->values[0].u16);
543*61046927SAndroid Build Coastguard Worker break;
544*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_UINT8: base_type = GLSL_TYPE_UINT; break;
545*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_UINT16: base_type = GLSL_TYPE_UINT; break;
546*61046927SAndroid Build Coastguard Worker default: unreachable("Unexpected base type");
547*61046927SAndroid Build Coastguard Worker }
548*61046927SAndroid Build Coastguard Worker break;
549*61046927SAndroid Build Coastguard Worker default: unreachable("Unexpected min bit size");
550*61046927SAndroid Build Coastguard Worker }
551*61046927SAndroid Build Coastguard Worker var->type = glsl_type_wrap_in_arrays(glsl_scalar_type(base_type), var->type);
552*61046927SAndroid Build Coastguard Worker return true;
553*61046927SAndroid Build Coastguard Worker }
554*61046927SAndroid Build Coastguard Worker if (glsl_base_type_bit_size(base_type) > max_bit_size) {
555*61046927SAndroid Build Coastguard Worker assert(!glsl_type_is_array_of_arrays(var->type));
556*61046927SAndroid Build Coastguard Worker var->type = glsl_array_type(glsl_scalar_type(GLSL_TYPE_UINT),
557*61046927SAndroid Build Coastguard Worker glsl_type_is_array(var->type) ? glsl_get_length(var->type) * 2 : 2,
558*61046927SAndroid Build Coastguard Worker 0);
559*61046927SAndroid Build Coastguard Worker if (var->constant_initializer) {
560*61046927SAndroid Build Coastguard Worker unsigned num_elements = var->constant_initializer->num_elements ?
561*61046927SAndroid Build Coastguard Worker var->constant_initializer->num_elements * 2 : 2;
562*61046927SAndroid Build Coastguard Worker nir_constant **element_arr = ralloc_array(var, nir_constant *, num_elements);
563*61046927SAndroid Build Coastguard Worker nir_constant *elements = rzalloc_array(var, nir_constant, num_elements);
564*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < var->constant_initializer->num_elements; ++i) {
565*61046927SAndroid Build Coastguard Worker element_arr[i*2] = &elements[i*2];
566*61046927SAndroid Build Coastguard Worker element_arr[i*2+1] = &elements[i*2+1];
567*61046927SAndroid Build Coastguard Worker const nir_const_value *src = var->constant_initializer->num_elements ?
568*61046927SAndroid Build Coastguard Worker var->constant_initializer->elements[i]->values : var->constant_initializer->values;
569*61046927SAndroid Build Coastguard Worker elements[i*2].values[0].u32 = (uint32_t)src->u64;
570*61046927SAndroid Build Coastguard Worker elements[i*2].is_null_constant = (uint32_t)src->u64 == 0;
571*61046927SAndroid Build Coastguard Worker elements[i*2+1].values[0].u32 = (uint32_t)(src->u64 >> 32);
572*61046927SAndroid Build Coastguard Worker elements[i*2+1].is_null_constant = (uint32_t)(src->u64 >> 32) == 0;
573*61046927SAndroid Build Coastguard Worker }
574*61046927SAndroid Build Coastguard Worker var->constant_initializer->num_elements = num_elements;
575*61046927SAndroid Build Coastguard Worker var->constant_initializer->elements = element_arr;
576*61046927SAndroid Build Coastguard Worker }
577*61046927SAndroid Build Coastguard Worker return true;
578*61046927SAndroid Build Coastguard Worker }
579*61046927SAndroid Build Coastguard Worker return false;
580*61046927SAndroid Build Coastguard Worker }
581*61046927SAndroid Build Coastguard Worker
582*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_var_bit_size(nir_shader * shader,nir_variable_mode modes,unsigned min_bit_size,unsigned max_bit_size)583*61046927SAndroid Build Coastguard Worker dxil_nir_lower_var_bit_size(nir_shader *shader, nir_variable_mode modes,
584*61046927SAndroid Build Coastguard Worker unsigned min_bit_size, unsigned max_bit_size)
585*61046927SAndroid Build Coastguard Worker {
586*61046927SAndroid Build Coastguard Worker bool progress = false;
587*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, shader, modes & ~nir_var_function_temp)
588*61046927SAndroid Build Coastguard Worker progress |= lower_var_bit_size_types(var, min_bit_size, max_bit_size);
589*61046927SAndroid Build Coastguard Worker
590*61046927SAndroid Build Coastguard Worker if (modes & nir_var_function_temp) {
591*61046927SAndroid Build Coastguard Worker nir_foreach_function_impl(impl, shader) {
592*61046927SAndroid Build Coastguard Worker nir_foreach_function_temp_variable(var, impl)
593*61046927SAndroid Build Coastguard Worker progress |= lower_var_bit_size_types(var, min_bit_size, max_bit_size);
594*61046927SAndroid Build Coastguard Worker }
595*61046927SAndroid Build Coastguard Worker }
596*61046927SAndroid Build Coastguard Worker
597*61046927SAndroid Build Coastguard Worker if (!progress)
598*61046927SAndroid Build Coastguard Worker return false;
599*61046927SAndroid Build Coastguard Worker
600*61046927SAndroid Build Coastguard Worker nir_shader_intrinsics_pass(shader, lower_deref_bit_size,
601*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow |
602*61046927SAndroid Build Coastguard Worker nir_metadata_loop_analysis,
603*61046927SAndroid Build Coastguard Worker NULL);
604*61046927SAndroid Build Coastguard Worker nir_remove_dead_derefs(shader);
605*61046927SAndroid Build Coastguard Worker return true;
606*61046927SAndroid Build Coastguard Worker }
607*61046927SAndroid Build Coastguard Worker
608*61046927SAndroid Build Coastguard Worker static bool
remove_oob_array_access(nir_builder * b,nir_intrinsic_instr * intr,void * data)609*61046927SAndroid Build Coastguard Worker remove_oob_array_access(nir_builder *b, nir_intrinsic_instr *intr, void *data)
610*61046927SAndroid Build Coastguard Worker {
611*61046927SAndroid Build Coastguard Worker uint32_t num_derefs = 1;
612*61046927SAndroid Build Coastguard Worker
613*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
614*61046927SAndroid Build Coastguard Worker case nir_intrinsic_copy_deref:
615*61046927SAndroid Build Coastguard Worker num_derefs = 2;
616*61046927SAndroid Build Coastguard Worker FALLTHROUGH;
617*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_deref:
618*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_deref:
619*61046927SAndroid Build Coastguard Worker case nir_intrinsic_deref_atomic:
620*61046927SAndroid Build Coastguard Worker case nir_intrinsic_deref_atomic_swap:
621*61046927SAndroid Build Coastguard Worker break;
622*61046927SAndroid Build Coastguard Worker default:
623*61046927SAndroid Build Coastguard Worker return false;
624*61046927SAndroid Build Coastguard Worker }
625*61046927SAndroid Build Coastguard Worker
626*61046927SAndroid Build Coastguard Worker for (uint32_t i = 0; i < num_derefs; ++i) {
627*61046927SAndroid Build Coastguard Worker if (nir_deref_instr_is_known_out_of_bounds(nir_src_as_deref(intr->src[i]))) {
628*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
629*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_deref:
630*61046927SAndroid Build Coastguard Worker case nir_intrinsic_deref_atomic:
631*61046927SAndroid Build Coastguard Worker case nir_intrinsic_deref_atomic_swap:
632*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
633*61046927SAndroid Build Coastguard Worker nir_def *undef = nir_undef(b, intr->def.num_components, intr->def.bit_size);
634*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&intr->def, undef);
635*61046927SAndroid Build Coastguard Worker break;
636*61046927SAndroid Build Coastguard Worker default:
637*61046927SAndroid Build Coastguard Worker break;
638*61046927SAndroid Build Coastguard Worker }
639*61046927SAndroid Build Coastguard Worker nir_instr_remove(&intr->instr);
640*61046927SAndroid Build Coastguard Worker return true;
641*61046927SAndroid Build Coastguard Worker }
642*61046927SAndroid Build Coastguard Worker }
643*61046927SAndroid Build Coastguard Worker
644*61046927SAndroid Build Coastguard Worker return false;
645*61046927SAndroid Build Coastguard Worker }
646*61046927SAndroid Build Coastguard Worker
647*61046927SAndroid Build Coastguard Worker bool
dxil_nir_remove_oob_array_accesses(nir_shader * shader)648*61046927SAndroid Build Coastguard Worker dxil_nir_remove_oob_array_accesses(nir_shader *shader)
649*61046927SAndroid Build Coastguard Worker {
650*61046927SAndroid Build Coastguard Worker return nir_shader_intrinsics_pass(shader, remove_oob_array_access,
651*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow |
652*61046927SAndroid Build Coastguard Worker nir_metadata_loop_analysis,
653*61046927SAndroid Build Coastguard Worker NULL);
654*61046927SAndroid Build Coastguard Worker }
655*61046927SAndroid Build Coastguard Worker
656*61046927SAndroid Build Coastguard Worker static bool
lower_shared_atomic(nir_builder * b,nir_intrinsic_instr * intr,nir_variable * var)657*61046927SAndroid Build Coastguard Worker lower_shared_atomic(nir_builder *b, nir_intrinsic_instr *intr, nir_variable *var)
658*61046927SAndroid Build Coastguard Worker {
659*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
660*61046927SAndroid Build Coastguard Worker
661*61046927SAndroid Build Coastguard Worker nir_def *offset =
662*61046927SAndroid Build Coastguard Worker nir_iadd_imm(b, intr->src[0].ssa, nir_intrinsic_base(intr));
663*61046927SAndroid Build Coastguard Worker nir_def *index = nir_ushr_imm(b, offset, 2);
664*61046927SAndroid Build Coastguard Worker
665*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_build_deref_array(b, nir_build_deref_var(b, var), index);
666*61046927SAndroid Build Coastguard Worker nir_def *result;
667*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_shared_atomic_swap)
668*61046927SAndroid Build Coastguard Worker result = nir_deref_atomic_swap(b, 32, &deref->def, intr->src[1].ssa, intr->src[2].ssa,
669*61046927SAndroid Build Coastguard Worker .atomic_op = nir_intrinsic_atomic_op(intr));
670*61046927SAndroid Build Coastguard Worker else
671*61046927SAndroid Build Coastguard Worker result = nir_deref_atomic(b, 32, &deref->def, intr->src[1].ssa,
672*61046927SAndroid Build Coastguard Worker .atomic_op = nir_intrinsic_atomic_op(intr));
673*61046927SAndroid Build Coastguard Worker
674*61046927SAndroid Build Coastguard Worker nir_def_replace(&intr->def, result);
675*61046927SAndroid Build Coastguard Worker return true;
676*61046927SAndroid Build Coastguard Worker }
677*61046927SAndroid Build Coastguard Worker
678*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_loads_stores_to_dxil(nir_shader * nir,const struct dxil_nir_lower_loads_stores_options * options)679*61046927SAndroid Build Coastguard Worker dxil_nir_lower_loads_stores_to_dxil(nir_shader *nir,
680*61046927SAndroid Build Coastguard Worker const struct dxil_nir_lower_loads_stores_options *options)
681*61046927SAndroid Build Coastguard Worker {
682*61046927SAndroid Build Coastguard Worker bool progress = nir_remove_dead_variables(nir, nir_var_function_temp | nir_var_mem_shared, NULL);
683*61046927SAndroid Build Coastguard Worker nir_variable *shared_var = NULL;
684*61046927SAndroid Build Coastguard Worker if (nir->info.shared_size) {
685*61046927SAndroid Build Coastguard Worker shared_var = nir_variable_create(nir, nir_var_mem_shared,
686*61046927SAndroid Build Coastguard Worker glsl_array_type(glsl_uint_type(), DIV_ROUND_UP(nir->info.shared_size, 4), 4),
687*61046927SAndroid Build Coastguard Worker "lowered_shared_mem");
688*61046927SAndroid Build Coastguard Worker }
689*61046927SAndroid Build Coastguard Worker
690*61046927SAndroid Build Coastguard Worker unsigned ptr_size = nir->info.cs.ptr_size;
691*61046927SAndroid Build Coastguard Worker if (nir->info.stage == MESA_SHADER_KERNEL) {
692*61046927SAndroid Build Coastguard Worker /* All the derefs created here will be used as GEP indices so force 32-bit */
693*61046927SAndroid Build Coastguard Worker nir->info.cs.ptr_size = 32;
694*61046927SAndroid Build Coastguard Worker }
695*61046927SAndroid Build Coastguard Worker nir_foreach_function_impl(impl, nir) {
696*61046927SAndroid Build Coastguard Worker nir_builder b = nir_builder_create(impl);
697*61046927SAndroid Build Coastguard Worker
698*61046927SAndroid Build Coastguard Worker nir_variable *scratch_var = NULL;
699*61046927SAndroid Build Coastguard Worker if (nir->scratch_size) {
700*61046927SAndroid Build Coastguard Worker const struct glsl_type *scratch_type = glsl_array_type(glsl_uint_type(), DIV_ROUND_UP(nir->scratch_size, 4), 4);
701*61046927SAndroid Build Coastguard Worker scratch_var = nir_local_variable_create(impl, scratch_type, "lowered_scratch_mem");
702*61046927SAndroid Build Coastguard Worker }
703*61046927SAndroid Build Coastguard Worker
704*61046927SAndroid Build Coastguard Worker nir_foreach_block(block, impl) {
705*61046927SAndroid Build Coastguard Worker nir_foreach_instr_safe(instr, block) {
706*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_intrinsic)
707*61046927SAndroid Build Coastguard Worker continue;
708*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
709*61046927SAndroid Build Coastguard Worker
710*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
711*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_shared:
712*61046927SAndroid Build Coastguard Worker progress |= lower_32b_offset_load(&b, intr, shared_var);
713*61046927SAndroid Build Coastguard Worker break;
714*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_scratch:
715*61046927SAndroid Build Coastguard Worker progress |= lower_32b_offset_load(&b, intr, scratch_var);
716*61046927SAndroid Build Coastguard Worker break;
717*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_shared:
718*61046927SAndroid Build Coastguard Worker progress |= lower_32b_offset_store(&b, intr, shared_var);
719*61046927SAndroid Build Coastguard Worker break;
720*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_scratch:
721*61046927SAndroid Build Coastguard Worker progress |= lower_32b_offset_store(&b, intr, scratch_var);
722*61046927SAndroid Build Coastguard Worker break;
723*61046927SAndroid Build Coastguard Worker case nir_intrinsic_shared_atomic:
724*61046927SAndroid Build Coastguard Worker case nir_intrinsic_shared_atomic_swap:
725*61046927SAndroid Build Coastguard Worker progress |= lower_shared_atomic(&b, intr, shared_var);
726*61046927SAndroid Build Coastguard Worker break;
727*61046927SAndroid Build Coastguard Worker default:
728*61046927SAndroid Build Coastguard Worker break;
729*61046927SAndroid Build Coastguard Worker }
730*61046927SAndroid Build Coastguard Worker }
731*61046927SAndroid Build Coastguard Worker }
732*61046927SAndroid Build Coastguard Worker }
733*61046927SAndroid Build Coastguard Worker if (nir->info.stage == MESA_SHADER_KERNEL) {
734*61046927SAndroid Build Coastguard Worker nir->info.cs.ptr_size = ptr_size;
735*61046927SAndroid Build Coastguard Worker }
736*61046927SAndroid Build Coastguard Worker
737*61046927SAndroid Build Coastguard Worker return progress;
738*61046927SAndroid Build Coastguard Worker }
739*61046927SAndroid Build Coastguard Worker
740*61046927SAndroid Build Coastguard Worker static bool
lower_deref_ssbo(nir_builder * b,nir_deref_instr * deref)741*61046927SAndroid Build Coastguard Worker lower_deref_ssbo(nir_builder *b, nir_deref_instr *deref)
742*61046927SAndroid Build Coastguard Worker {
743*61046927SAndroid Build Coastguard Worker assert(nir_deref_mode_is(deref, nir_var_mem_ssbo));
744*61046927SAndroid Build Coastguard Worker assert(deref->deref_type == nir_deref_type_var ||
745*61046927SAndroid Build Coastguard Worker deref->deref_type == nir_deref_type_cast);
746*61046927SAndroid Build Coastguard Worker nir_variable *var = deref->var;
747*61046927SAndroid Build Coastguard Worker
748*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&deref->instr);
749*61046927SAndroid Build Coastguard Worker
750*61046927SAndroid Build Coastguard Worker if (deref->deref_type == nir_deref_type_var) {
751*61046927SAndroid Build Coastguard Worker /* We turn all deref_var into deref_cast and build a pointer value based on
752*61046927SAndroid Build Coastguard Worker * the var binding which encodes the UAV id.
753*61046927SAndroid Build Coastguard Worker */
754*61046927SAndroid Build Coastguard Worker nir_def *ptr = nir_imm_int64(b, (uint64_t)var->data.binding << 32);
755*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref_cast =
756*61046927SAndroid Build Coastguard Worker nir_build_deref_cast(b, ptr, nir_var_mem_ssbo, deref->type,
757*61046927SAndroid Build Coastguard Worker glsl_get_explicit_stride(var->type));
758*61046927SAndroid Build Coastguard Worker nir_def_replace(&deref->def, &deref_cast->def);
759*61046927SAndroid Build Coastguard Worker
760*61046927SAndroid Build Coastguard Worker deref = deref_cast;
761*61046927SAndroid Build Coastguard Worker return true;
762*61046927SAndroid Build Coastguard Worker }
763*61046927SAndroid Build Coastguard Worker return false;
764*61046927SAndroid Build Coastguard Worker }
765*61046927SAndroid Build Coastguard Worker
766*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_deref_ssbo(nir_shader * nir)767*61046927SAndroid Build Coastguard Worker dxil_nir_lower_deref_ssbo(nir_shader *nir)
768*61046927SAndroid Build Coastguard Worker {
769*61046927SAndroid Build Coastguard Worker bool progress = false;
770*61046927SAndroid Build Coastguard Worker
771*61046927SAndroid Build Coastguard Worker foreach_list_typed(nir_function, func, node, &nir->functions) {
772*61046927SAndroid Build Coastguard Worker if (!func->is_entrypoint)
773*61046927SAndroid Build Coastguard Worker continue;
774*61046927SAndroid Build Coastguard Worker assert(func->impl);
775*61046927SAndroid Build Coastguard Worker
776*61046927SAndroid Build Coastguard Worker nir_builder b = nir_builder_create(func->impl);
777*61046927SAndroid Build Coastguard Worker
778*61046927SAndroid Build Coastguard Worker nir_foreach_block(block, func->impl) {
779*61046927SAndroid Build Coastguard Worker nir_foreach_instr_safe(instr, block) {
780*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_deref)
781*61046927SAndroid Build Coastguard Worker continue;
782*61046927SAndroid Build Coastguard Worker
783*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_instr_as_deref(instr);
784*61046927SAndroid Build Coastguard Worker
785*61046927SAndroid Build Coastguard Worker if (!nir_deref_mode_is(deref, nir_var_mem_ssbo) ||
786*61046927SAndroid Build Coastguard Worker (deref->deref_type != nir_deref_type_var &&
787*61046927SAndroid Build Coastguard Worker deref->deref_type != nir_deref_type_cast))
788*61046927SAndroid Build Coastguard Worker continue;
789*61046927SAndroid Build Coastguard Worker
790*61046927SAndroid Build Coastguard Worker progress |= lower_deref_ssbo(&b, deref);
791*61046927SAndroid Build Coastguard Worker }
792*61046927SAndroid Build Coastguard Worker }
793*61046927SAndroid Build Coastguard Worker }
794*61046927SAndroid Build Coastguard Worker
795*61046927SAndroid Build Coastguard Worker return progress;
796*61046927SAndroid Build Coastguard Worker }
797*61046927SAndroid Build Coastguard Worker
798*61046927SAndroid Build Coastguard Worker static bool
lower_alu_deref_srcs(nir_builder * b,nir_alu_instr * alu)799*61046927SAndroid Build Coastguard Worker lower_alu_deref_srcs(nir_builder *b, nir_alu_instr *alu)
800*61046927SAndroid Build Coastguard Worker {
801*61046927SAndroid Build Coastguard Worker const nir_op_info *info = &nir_op_infos[alu->op];
802*61046927SAndroid Build Coastguard Worker bool progress = false;
803*61046927SAndroid Build Coastguard Worker
804*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&alu->instr);
805*61046927SAndroid Build Coastguard Worker
806*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < info->num_inputs; i++) {
807*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_src_as_deref(alu->src[i].src);
808*61046927SAndroid Build Coastguard Worker
809*61046927SAndroid Build Coastguard Worker if (!deref)
810*61046927SAndroid Build Coastguard Worker continue;
811*61046927SAndroid Build Coastguard Worker
812*61046927SAndroid Build Coastguard Worker nir_deref_path path;
813*61046927SAndroid Build Coastguard Worker nir_deref_path_init(&path, deref, NULL);
814*61046927SAndroid Build Coastguard Worker nir_deref_instr *root_deref = path.path[0];
815*61046927SAndroid Build Coastguard Worker nir_deref_path_finish(&path);
816*61046927SAndroid Build Coastguard Worker
817*61046927SAndroid Build Coastguard Worker if (root_deref->deref_type != nir_deref_type_cast)
818*61046927SAndroid Build Coastguard Worker continue;
819*61046927SAndroid Build Coastguard Worker
820*61046927SAndroid Build Coastguard Worker nir_def *ptr =
821*61046927SAndroid Build Coastguard Worker nir_iadd(b, root_deref->parent.ssa,
822*61046927SAndroid Build Coastguard Worker nir_build_deref_offset(b, deref, cl_type_size_align));
823*61046927SAndroid Build Coastguard Worker nir_src_rewrite(&alu->src[i].src, ptr);
824*61046927SAndroid Build Coastguard Worker progress = true;
825*61046927SAndroid Build Coastguard Worker }
826*61046927SAndroid Build Coastguard Worker
827*61046927SAndroid Build Coastguard Worker return progress;
828*61046927SAndroid Build Coastguard Worker }
829*61046927SAndroid Build Coastguard Worker
830*61046927SAndroid Build Coastguard Worker bool
dxil_nir_opt_alu_deref_srcs(nir_shader * nir)831*61046927SAndroid Build Coastguard Worker dxil_nir_opt_alu_deref_srcs(nir_shader *nir)
832*61046927SAndroid Build Coastguard Worker {
833*61046927SAndroid Build Coastguard Worker bool progress = false;
834*61046927SAndroid Build Coastguard Worker
835*61046927SAndroid Build Coastguard Worker foreach_list_typed(nir_function, func, node, &nir->functions) {
836*61046927SAndroid Build Coastguard Worker if (!func->is_entrypoint)
837*61046927SAndroid Build Coastguard Worker continue;
838*61046927SAndroid Build Coastguard Worker assert(func->impl);
839*61046927SAndroid Build Coastguard Worker
840*61046927SAndroid Build Coastguard Worker nir_builder b = nir_builder_create(func->impl);
841*61046927SAndroid Build Coastguard Worker
842*61046927SAndroid Build Coastguard Worker nir_foreach_block(block, func->impl) {
843*61046927SAndroid Build Coastguard Worker nir_foreach_instr_safe(instr, block) {
844*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_alu)
845*61046927SAndroid Build Coastguard Worker continue;
846*61046927SAndroid Build Coastguard Worker
847*61046927SAndroid Build Coastguard Worker nir_alu_instr *alu = nir_instr_as_alu(instr);
848*61046927SAndroid Build Coastguard Worker progress |= lower_alu_deref_srcs(&b, alu);
849*61046927SAndroid Build Coastguard Worker }
850*61046927SAndroid Build Coastguard Worker }
851*61046927SAndroid Build Coastguard Worker }
852*61046927SAndroid Build Coastguard Worker
853*61046927SAndroid Build Coastguard Worker return progress;
854*61046927SAndroid Build Coastguard Worker }
855*61046927SAndroid Build Coastguard Worker
856*61046927SAndroid Build Coastguard Worker static void
cast_phi(nir_builder * b,nir_phi_instr * phi,unsigned new_bit_size)857*61046927SAndroid Build Coastguard Worker cast_phi(nir_builder *b, nir_phi_instr *phi, unsigned new_bit_size)
858*61046927SAndroid Build Coastguard Worker {
859*61046927SAndroid Build Coastguard Worker nir_phi_instr *lowered = nir_phi_instr_create(b->shader);
860*61046927SAndroid Build Coastguard Worker int num_components = 0;
861*61046927SAndroid Build Coastguard Worker int old_bit_size = phi->def.bit_size;
862*61046927SAndroid Build Coastguard Worker
863*61046927SAndroid Build Coastguard Worker nir_foreach_phi_src(src, phi) {
864*61046927SAndroid Build Coastguard Worker assert(num_components == 0 || num_components == src->src.ssa->num_components);
865*61046927SAndroid Build Coastguard Worker num_components = src->src.ssa->num_components;
866*61046927SAndroid Build Coastguard Worker
867*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr_and_phis(src->src.ssa->parent_instr);
868*61046927SAndroid Build Coastguard Worker
869*61046927SAndroid Build Coastguard Worker nir_def *cast = nir_u2uN(b, src->src.ssa, new_bit_size);
870*61046927SAndroid Build Coastguard Worker
871*61046927SAndroid Build Coastguard Worker nir_phi_instr_add_src(lowered, src->pred, cast);
872*61046927SAndroid Build Coastguard Worker }
873*61046927SAndroid Build Coastguard Worker
874*61046927SAndroid Build Coastguard Worker nir_def_init(&lowered->instr, &lowered->def, num_components,
875*61046927SAndroid Build Coastguard Worker new_bit_size);
876*61046927SAndroid Build Coastguard Worker
877*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&phi->instr);
878*61046927SAndroid Build Coastguard Worker nir_builder_instr_insert(b, &lowered->instr);
879*61046927SAndroid Build Coastguard Worker
880*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_phis(nir_cursor_current_block(b->cursor));
881*61046927SAndroid Build Coastguard Worker nir_def *result = nir_u2uN(b, &lowered->def, old_bit_size);
882*61046927SAndroid Build Coastguard Worker
883*61046927SAndroid Build Coastguard Worker nir_def_replace(&phi->def, result);
884*61046927SAndroid Build Coastguard Worker }
885*61046927SAndroid Build Coastguard Worker
886*61046927SAndroid Build Coastguard Worker static bool
upcast_phi_impl(nir_function_impl * impl,unsigned min_bit_size)887*61046927SAndroid Build Coastguard Worker upcast_phi_impl(nir_function_impl *impl, unsigned min_bit_size)
888*61046927SAndroid Build Coastguard Worker {
889*61046927SAndroid Build Coastguard Worker nir_builder b = nir_builder_create(impl);
890*61046927SAndroid Build Coastguard Worker bool progress = false;
891*61046927SAndroid Build Coastguard Worker
892*61046927SAndroid Build Coastguard Worker nir_foreach_block_reverse(block, impl) {
893*61046927SAndroid Build Coastguard Worker nir_foreach_phi_safe(phi, block) {
894*61046927SAndroid Build Coastguard Worker if (phi->def.bit_size == 1 ||
895*61046927SAndroid Build Coastguard Worker phi->def.bit_size >= min_bit_size)
896*61046927SAndroid Build Coastguard Worker continue;
897*61046927SAndroid Build Coastguard Worker
898*61046927SAndroid Build Coastguard Worker cast_phi(&b, phi, min_bit_size);
899*61046927SAndroid Build Coastguard Worker progress = true;
900*61046927SAndroid Build Coastguard Worker }
901*61046927SAndroid Build Coastguard Worker }
902*61046927SAndroid Build Coastguard Worker
903*61046927SAndroid Build Coastguard Worker if (progress) {
904*61046927SAndroid Build Coastguard Worker nir_metadata_preserve(impl, nir_metadata_control_flow);
905*61046927SAndroid Build Coastguard Worker } else {
906*61046927SAndroid Build Coastguard Worker nir_metadata_preserve(impl, nir_metadata_all);
907*61046927SAndroid Build Coastguard Worker }
908*61046927SAndroid Build Coastguard Worker
909*61046927SAndroid Build Coastguard Worker return progress;
910*61046927SAndroid Build Coastguard Worker }
911*61046927SAndroid Build Coastguard Worker
912*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_upcast_phis(nir_shader * shader,unsigned min_bit_size)913*61046927SAndroid Build Coastguard Worker dxil_nir_lower_upcast_phis(nir_shader *shader, unsigned min_bit_size)
914*61046927SAndroid Build Coastguard Worker {
915*61046927SAndroid Build Coastguard Worker bool progress = false;
916*61046927SAndroid Build Coastguard Worker
917*61046927SAndroid Build Coastguard Worker nir_foreach_function_impl(impl, shader) {
918*61046927SAndroid Build Coastguard Worker progress |= upcast_phi_impl(impl, min_bit_size);
919*61046927SAndroid Build Coastguard Worker }
920*61046927SAndroid Build Coastguard Worker
921*61046927SAndroid Build Coastguard Worker return progress;
922*61046927SAndroid Build Coastguard Worker }
923*61046927SAndroid Build Coastguard Worker
924*61046927SAndroid Build Coastguard Worker struct dxil_nir_split_clip_cull_distance_params {
925*61046927SAndroid Build Coastguard Worker nir_variable *new_var[2];
926*61046927SAndroid Build Coastguard Worker nir_shader *shader;
927*61046927SAndroid Build Coastguard Worker };
928*61046927SAndroid Build Coastguard Worker
929*61046927SAndroid Build Coastguard Worker /* In GLSL and SPIR-V, clip and cull distance are arrays of floats (with a limit of 8).
930*61046927SAndroid Build Coastguard Worker * In DXIL, clip and cull distances are up to 2 float4s combined.
931*61046927SAndroid Build Coastguard Worker * Coming from GLSL, we can request this 2 float4 format, but coming from SPIR-V,
932*61046927SAndroid Build Coastguard Worker * we can't, and have to accept a "compact" array of scalar floats.
933*61046927SAndroid Build Coastguard Worker *
934*61046927SAndroid Build Coastguard Worker * To help emitting a valid input signature for this case, split the variables so that they
935*61046927SAndroid Build Coastguard Worker * match what we need to put in the signature (e.g. { float clip[4]; float clip1; float cull[3]; })
936*61046927SAndroid Build Coastguard Worker */
937*61046927SAndroid Build Coastguard Worker static bool
dxil_nir_split_clip_cull_distance_instr(nir_builder * b,nir_instr * instr,void * cb_data)938*61046927SAndroid Build Coastguard Worker dxil_nir_split_clip_cull_distance_instr(nir_builder *b,
939*61046927SAndroid Build Coastguard Worker nir_instr *instr,
940*61046927SAndroid Build Coastguard Worker void *cb_data)
941*61046927SAndroid Build Coastguard Worker {
942*61046927SAndroid Build Coastguard Worker struct dxil_nir_split_clip_cull_distance_params *params = cb_data;
943*61046927SAndroid Build Coastguard Worker
944*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_deref)
945*61046927SAndroid Build Coastguard Worker return false;
946*61046927SAndroid Build Coastguard Worker
947*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_instr_as_deref(instr);
948*61046927SAndroid Build Coastguard Worker nir_variable *var = nir_deref_instr_get_variable(deref);
949*61046927SAndroid Build Coastguard Worker if (!var ||
950*61046927SAndroid Build Coastguard Worker var->data.location < VARYING_SLOT_CLIP_DIST0 ||
951*61046927SAndroid Build Coastguard Worker var->data.location > VARYING_SLOT_CULL_DIST1 ||
952*61046927SAndroid Build Coastguard Worker !var->data.compact)
953*61046927SAndroid Build Coastguard Worker return false;
954*61046927SAndroid Build Coastguard Worker
955*61046927SAndroid Build Coastguard Worker unsigned new_var_idx = var->data.mode == nir_var_shader_in ? 0 : 1;
956*61046927SAndroid Build Coastguard Worker nir_variable *new_var = params->new_var[new_var_idx];
957*61046927SAndroid Build Coastguard Worker
958*61046927SAndroid Build Coastguard Worker /* The location should only be inside clip distance, because clip
959*61046927SAndroid Build Coastguard Worker * and cull should've been merged by nir_lower_clip_cull_distance_arrays()
960*61046927SAndroid Build Coastguard Worker */
961*61046927SAndroid Build Coastguard Worker assert(var->data.location == VARYING_SLOT_CLIP_DIST0 ||
962*61046927SAndroid Build Coastguard Worker var->data.location == VARYING_SLOT_CLIP_DIST1);
963*61046927SAndroid Build Coastguard Worker
964*61046927SAndroid Build Coastguard Worker /* The deref chain to the clip/cull variables should be simple, just the
965*61046927SAndroid Build Coastguard Worker * var and an array with a constant index, otherwise more lowering/optimization
966*61046927SAndroid Build Coastguard Worker * might be needed before this pass, e.g. copy prop, lower_io_to_temporaries,
967*61046927SAndroid Build Coastguard Worker * split_var_copies, and/or lower_var_copies. In the case of arrayed I/O like
968*61046927SAndroid Build Coastguard Worker * inputs to the tessellation or geometry stages, there might be a second level
969*61046927SAndroid Build Coastguard Worker * of array index.
970*61046927SAndroid Build Coastguard Worker */
971*61046927SAndroid Build Coastguard Worker assert(deref->deref_type == nir_deref_type_var ||
972*61046927SAndroid Build Coastguard Worker deref->deref_type == nir_deref_type_array);
973*61046927SAndroid Build Coastguard Worker
974*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(instr);
975*61046927SAndroid Build Coastguard Worker unsigned arrayed_io_length = 0;
976*61046927SAndroid Build Coastguard Worker const struct glsl_type *old_type = var->type;
977*61046927SAndroid Build Coastguard Worker if (nir_is_arrayed_io(var, b->shader->info.stage)) {
978*61046927SAndroid Build Coastguard Worker arrayed_io_length = glsl_array_size(old_type);
979*61046927SAndroid Build Coastguard Worker old_type = glsl_get_array_element(old_type);
980*61046927SAndroid Build Coastguard Worker }
981*61046927SAndroid Build Coastguard Worker if (!new_var) {
982*61046927SAndroid Build Coastguard Worker /* Update lengths for new and old vars */
983*61046927SAndroid Build Coastguard Worker int old_length = glsl_array_size(old_type);
984*61046927SAndroid Build Coastguard Worker int new_length = (old_length + var->data.location_frac) - 4;
985*61046927SAndroid Build Coastguard Worker old_length -= new_length;
986*61046927SAndroid Build Coastguard Worker
987*61046927SAndroid Build Coastguard Worker /* The existing variable fits in the float4 */
988*61046927SAndroid Build Coastguard Worker if (new_length <= 0)
989*61046927SAndroid Build Coastguard Worker return false;
990*61046927SAndroid Build Coastguard Worker
991*61046927SAndroid Build Coastguard Worker new_var = nir_variable_clone(var, params->shader);
992*61046927SAndroid Build Coastguard Worker nir_shader_add_variable(params->shader, new_var);
993*61046927SAndroid Build Coastguard Worker assert(glsl_get_base_type(glsl_get_array_element(old_type)) == GLSL_TYPE_FLOAT);
994*61046927SAndroid Build Coastguard Worker var->type = glsl_array_type(glsl_float_type(), old_length, 0);
995*61046927SAndroid Build Coastguard Worker new_var->type = glsl_array_type(glsl_float_type(), new_length, 0);
996*61046927SAndroid Build Coastguard Worker if (arrayed_io_length) {
997*61046927SAndroid Build Coastguard Worker var->type = glsl_array_type(var->type, arrayed_io_length, 0);
998*61046927SAndroid Build Coastguard Worker new_var->type = glsl_array_type(new_var->type, arrayed_io_length, 0);
999*61046927SAndroid Build Coastguard Worker }
1000*61046927SAndroid Build Coastguard Worker new_var->data.location++;
1001*61046927SAndroid Build Coastguard Worker new_var->data.location_frac = 0;
1002*61046927SAndroid Build Coastguard Worker params->new_var[new_var_idx] = new_var;
1003*61046927SAndroid Build Coastguard Worker }
1004*61046927SAndroid Build Coastguard Worker
1005*61046927SAndroid Build Coastguard Worker /* Update the type for derefs of the old var */
1006*61046927SAndroid Build Coastguard Worker if (deref->deref_type == nir_deref_type_var) {
1007*61046927SAndroid Build Coastguard Worker deref->type = var->type;
1008*61046927SAndroid Build Coastguard Worker return false;
1009*61046927SAndroid Build Coastguard Worker }
1010*61046927SAndroid Build Coastguard Worker
1011*61046927SAndroid Build Coastguard Worker if (glsl_type_is_array(deref->type)) {
1012*61046927SAndroid Build Coastguard Worker assert(arrayed_io_length > 0);
1013*61046927SAndroid Build Coastguard Worker deref->type = glsl_get_array_element(var->type);
1014*61046927SAndroid Build Coastguard Worker return false;
1015*61046927SAndroid Build Coastguard Worker }
1016*61046927SAndroid Build Coastguard Worker
1017*61046927SAndroid Build Coastguard Worker assert(glsl_get_base_type(deref->type) == GLSL_TYPE_FLOAT);
1018*61046927SAndroid Build Coastguard Worker
1019*61046927SAndroid Build Coastguard Worker nir_const_value *index = nir_src_as_const_value(deref->arr.index);
1020*61046927SAndroid Build Coastguard Worker assert(index);
1021*61046927SAndroid Build Coastguard Worker
1022*61046927SAndroid Build Coastguard Worker /* Treat this array as a vector starting at the component index in location_frac,
1023*61046927SAndroid Build Coastguard Worker * so if location_frac is 1 and index is 0, then it's accessing the 'y' component
1024*61046927SAndroid Build Coastguard Worker * of the vector. If index + location_frac is >= 4, there's no component there,
1025*61046927SAndroid Build Coastguard Worker * so we need to add a new variable and adjust the index.
1026*61046927SAndroid Build Coastguard Worker */
1027*61046927SAndroid Build Coastguard Worker unsigned total_index = index->u32 + var->data.location_frac;
1028*61046927SAndroid Build Coastguard Worker if (total_index < 4)
1029*61046927SAndroid Build Coastguard Worker return false;
1030*61046927SAndroid Build Coastguard Worker
1031*61046927SAndroid Build Coastguard Worker nir_deref_instr *new_var_deref = nir_build_deref_var(b, new_var);
1032*61046927SAndroid Build Coastguard Worker nir_deref_instr *new_intermediate_deref = new_var_deref;
1033*61046927SAndroid Build Coastguard Worker if (arrayed_io_length) {
1034*61046927SAndroid Build Coastguard Worker nir_deref_instr *parent = nir_src_as_deref(deref->parent);
1035*61046927SAndroid Build Coastguard Worker assert(parent->deref_type == nir_deref_type_array);
1036*61046927SAndroid Build Coastguard Worker new_intermediate_deref = nir_build_deref_array(b, new_intermediate_deref, parent->arr.index.ssa);
1037*61046927SAndroid Build Coastguard Worker }
1038*61046927SAndroid Build Coastguard Worker nir_deref_instr *new_array_deref = nir_build_deref_array(b, new_intermediate_deref, nir_imm_int(b, total_index % 4));
1039*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&deref->def, &new_array_deref->def);
1040*61046927SAndroid Build Coastguard Worker return true;
1041*61046927SAndroid Build Coastguard Worker }
1042*61046927SAndroid Build Coastguard Worker
1043*61046927SAndroid Build Coastguard Worker bool
dxil_nir_split_clip_cull_distance(nir_shader * shader)1044*61046927SAndroid Build Coastguard Worker dxil_nir_split_clip_cull_distance(nir_shader *shader)
1045*61046927SAndroid Build Coastguard Worker {
1046*61046927SAndroid Build Coastguard Worker struct dxil_nir_split_clip_cull_distance_params params = {
1047*61046927SAndroid Build Coastguard Worker .new_var = { NULL, NULL },
1048*61046927SAndroid Build Coastguard Worker .shader = shader,
1049*61046927SAndroid Build Coastguard Worker };
1050*61046927SAndroid Build Coastguard Worker nir_shader_instructions_pass(shader,
1051*61046927SAndroid Build Coastguard Worker dxil_nir_split_clip_cull_distance_instr,
1052*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow |
1053*61046927SAndroid Build Coastguard Worker nir_metadata_loop_analysis,
1054*61046927SAndroid Build Coastguard Worker ¶ms);
1055*61046927SAndroid Build Coastguard Worker return params.new_var[0] != NULL || params.new_var[1] != NULL;
1056*61046927SAndroid Build Coastguard Worker }
1057*61046927SAndroid Build Coastguard Worker
1058*61046927SAndroid Build Coastguard Worker static bool
dxil_nir_lower_double_math_instr(nir_builder * b,nir_instr * instr,UNUSED void * cb_data)1059*61046927SAndroid Build Coastguard Worker dxil_nir_lower_double_math_instr(nir_builder *b,
1060*61046927SAndroid Build Coastguard Worker nir_instr *instr,
1061*61046927SAndroid Build Coastguard Worker UNUSED void *cb_data)
1062*61046927SAndroid Build Coastguard Worker {
1063*61046927SAndroid Build Coastguard Worker if (instr->type == nir_instr_type_intrinsic) {
1064*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
1065*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
1066*61046927SAndroid Build Coastguard Worker case nir_intrinsic_reduce:
1067*61046927SAndroid Build Coastguard Worker case nir_intrinsic_exclusive_scan:
1068*61046927SAndroid Build Coastguard Worker case nir_intrinsic_inclusive_scan:
1069*61046927SAndroid Build Coastguard Worker break;
1070*61046927SAndroid Build Coastguard Worker default:
1071*61046927SAndroid Build Coastguard Worker return false;
1072*61046927SAndroid Build Coastguard Worker }
1073*61046927SAndroid Build Coastguard Worker if (intr->def.bit_size != 64)
1074*61046927SAndroid Build Coastguard Worker return false;
1075*61046927SAndroid Build Coastguard Worker nir_op reduction = nir_intrinsic_reduction_op(intr);
1076*61046927SAndroid Build Coastguard Worker switch (reduction) {
1077*61046927SAndroid Build Coastguard Worker case nir_op_fmul:
1078*61046927SAndroid Build Coastguard Worker case nir_op_fadd:
1079*61046927SAndroid Build Coastguard Worker case nir_op_fmin:
1080*61046927SAndroid Build Coastguard Worker case nir_op_fmax:
1081*61046927SAndroid Build Coastguard Worker break;
1082*61046927SAndroid Build Coastguard Worker default:
1083*61046927SAndroid Build Coastguard Worker return false;
1084*61046927SAndroid Build Coastguard Worker }
1085*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(instr);
1086*61046927SAndroid Build Coastguard Worker nir_src_rewrite(&intr->src[0], nir_pack_double_2x32_dxil(b, nir_unpack_64_2x32(b, intr->src[0].ssa)));
1087*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(instr);
1088*61046927SAndroid Build Coastguard Worker nir_def *result = nir_pack_64_2x32(b, nir_unpack_double_2x32_dxil(b, &intr->def));
1089*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses_after(&intr->def, result, result->parent_instr);
1090*61046927SAndroid Build Coastguard Worker return true;
1091*61046927SAndroid Build Coastguard Worker }
1092*61046927SAndroid Build Coastguard Worker
1093*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_alu)
1094*61046927SAndroid Build Coastguard Worker return false;
1095*61046927SAndroid Build Coastguard Worker
1096*61046927SAndroid Build Coastguard Worker nir_alu_instr *alu = nir_instr_as_alu(instr);
1097*61046927SAndroid Build Coastguard Worker
1098*61046927SAndroid Build Coastguard Worker /* TODO: See if we can apply this explicitly to packs/unpacks that are then
1099*61046927SAndroid Build Coastguard Worker * used as a double. As-is, if we had an app explicitly do a 64bit integer op,
1100*61046927SAndroid Build Coastguard Worker * then try to bitcast to double (not expressible in HLSL, but it is in other
1101*61046927SAndroid Build Coastguard Worker * source languages), this would unpack the integer and repack as a double, when
1102*61046927SAndroid Build Coastguard Worker * we probably want to just send the bitcast through to the backend.
1103*61046927SAndroid Build Coastguard Worker */
1104*61046927SAndroid Build Coastguard Worker
1105*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&alu->instr);
1106*61046927SAndroid Build Coastguard Worker
1107*61046927SAndroid Build Coastguard Worker bool progress = false;
1108*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; ++i) {
1109*61046927SAndroid Build Coastguard Worker if (nir_alu_type_get_base_type(nir_op_infos[alu->op].input_types[i]) == nir_type_float &&
1110*61046927SAndroid Build Coastguard Worker alu->src[i].src.ssa->bit_size == 64) {
1111*61046927SAndroid Build Coastguard Worker unsigned num_components = nir_op_infos[alu->op].input_sizes[i];
1112*61046927SAndroid Build Coastguard Worker if (!num_components)
1113*61046927SAndroid Build Coastguard Worker num_components = alu->def.num_components;
1114*61046927SAndroid Build Coastguard Worker nir_def *components[NIR_MAX_VEC_COMPONENTS];
1115*61046927SAndroid Build Coastguard Worker for (unsigned c = 0; c < num_components; ++c) {
1116*61046927SAndroid Build Coastguard Worker nir_def *packed_double = nir_channel(b, alu->src[i].src.ssa, alu->src[i].swizzle[c]);
1117*61046927SAndroid Build Coastguard Worker nir_def *unpacked_double = nir_unpack_64_2x32(b, packed_double);
1118*61046927SAndroid Build Coastguard Worker components[c] = nir_pack_double_2x32_dxil(b, unpacked_double);
1119*61046927SAndroid Build Coastguard Worker alu->src[i].swizzle[c] = c;
1120*61046927SAndroid Build Coastguard Worker }
1121*61046927SAndroid Build Coastguard Worker nir_src_rewrite(&alu->src[i].src,
1122*61046927SAndroid Build Coastguard Worker nir_vec(b, components, num_components));
1123*61046927SAndroid Build Coastguard Worker progress = true;
1124*61046927SAndroid Build Coastguard Worker }
1125*61046927SAndroid Build Coastguard Worker }
1126*61046927SAndroid Build Coastguard Worker
1127*61046927SAndroid Build Coastguard Worker if (nir_alu_type_get_base_type(nir_op_infos[alu->op].output_type) == nir_type_float &&
1128*61046927SAndroid Build Coastguard Worker alu->def.bit_size == 64) {
1129*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(&alu->instr);
1130*61046927SAndroid Build Coastguard Worker nir_def *components[NIR_MAX_VEC_COMPONENTS];
1131*61046927SAndroid Build Coastguard Worker for (unsigned c = 0; c < alu->def.num_components; ++c) {
1132*61046927SAndroid Build Coastguard Worker nir_def *packed_double = nir_channel(b, &alu->def, c);
1133*61046927SAndroid Build Coastguard Worker nir_def *unpacked_double = nir_unpack_double_2x32_dxil(b, packed_double);
1134*61046927SAndroid Build Coastguard Worker components[c] = nir_pack_64_2x32(b, unpacked_double);
1135*61046927SAndroid Build Coastguard Worker }
1136*61046927SAndroid Build Coastguard Worker nir_def *repacked_dvec = nir_vec(b, components, alu->def.num_components);
1137*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses_after(&alu->def, repacked_dvec, repacked_dvec->parent_instr);
1138*61046927SAndroid Build Coastguard Worker progress = true;
1139*61046927SAndroid Build Coastguard Worker }
1140*61046927SAndroid Build Coastguard Worker
1141*61046927SAndroid Build Coastguard Worker return progress;
1142*61046927SAndroid Build Coastguard Worker }
1143*61046927SAndroid Build Coastguard Worker
1144*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_double_math(nir_shader * shader)1145*61046927SAndroid Build Coastguard Worker dxil_nir_lower_double_math(nir_shader *shader)
1146*61046927SAndroid Build Coastguard Worker {
1147*61046927SAndroid Build Coastguard Worker return nir_shader_instructions_pass(shader,
1148*61046927SAndroid Build Coastguard Worker dxil_nir_lower_double_math_instr,
1149*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow |
1150*61046927SAndroid Build Coastguard Worker nir_metadata_loop_analysis,
1151*61046927SAndroid Build Coastguard Worker NULL);
1152*61046927SAndroid Build Coastguard Worker }
1153*61046927SAndroid Build Coastguard Worker
1154*61046927SAndroid Build Coastguard Worker typedef struct {
1155*61046927SAndroid Build Coastguard Worker gl_system_value *values;
1156*61046927SAndroid Build Coastguard Worker uint32_t count;
1157*61046927SAndroid Build Coastguard Worker } zero_system_values_state;
1158*61046927SAndroid Build Coastguard Worker
1159*61046927SAndroid Build Coastguard Worker static bool
lower_system_value_to_zero_filter(const nir_instr * instr,const void * cb_state)1160*61046927SAndroid Build Coastguard Worker lower_system_value_to_zero_filter(const nir_instr* instr, const void* cb_state)
1161*61046927SAndroid Build Coastguard Worker {
1162*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_intrinsic) {
1163*61046927SAndroid Build Coastguard Worker return false;
1164*61046927SAndroid Build Coastguard Worker }
1165*61046927SAndroid Build Coastguard Worker
1166*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr* intrin = nir_instr_as_intrinsic(instr);
1167*61046927SAndroid Build Coastguard Worker
1168*61046927SAndroid Build Coastguard Worker /* All the intrinsics we care about are loads */
1169*61046927SAndroid Build Coastguard Worker if (!nir_intrinsic_infos[intrin->intrinsic].has_dest)
1170*61046927SAndroid Build Coastguard Worker return false;
1171*61046927SAndroid Build Coastguard Worker
1172*61046927SAndroid Build Coastguard Worker zero_system_values_state* state = (zero_system_values_state*)cb_state;
1173*61046927SAndroid Build Coastguard Worker for (uint32_t i = 0; i < state->count; ++i) {
1174*61046927SAndroid Build Coastguard Worker gl_system_value value = state->values[i];
1175*61046927SAndroid Build Coastguard Worker nir_intrinsic_op value_op = nir_intrinsic_from_system_value(value);
1176*61046927SAndroid Build Coastguard Worker
1177*61046927SAndroid Build Coastguard Worker if (intrin->intrinsic == value_op) {
1178*61046927SAndroid Build Coastguard Worker return true;
1179*61046927SAndroid Build Coastguard Worker } else if (intrin->intrinsic == nir_intrinsic_load_deref) {
1180*61046927SAndroid Build Coastguard Worker nir_deref_instr* deref = nir_src_as_deref(intrin->src[0]);
1181*61046927SAndroid Build Coastguard Worker if (!nir_deref_mode_is(deref, nir_var_system_value))
1182*61046927SAndroid Build Coastguard Worker return false;
1183*61046927SAndroid Build Coastguard Worker
1184*61046927SAndroid Build Coastguard Worker nir_variable* var = deref->var;
1185*61046927SAndroid Build Coastguard Worker if (var->data.location == value) {
1186*61046927SAndroid Build Coastguard Worker return true;
1187*61046927SAndroid Build Coastguard Worker }
1188*61046927SAndroid Build Coastguard Worker }
1189*61046927SAndroid Build Coastguard Worker }
1190*61046927SAndroid Build Coastguard Worker
1191*61046927SAndroid Build Coastguard Worker return false;
1192*61046927SAndroid Build Coastguard Worker }
1193*61046927SAndroid Build Coastguard Worker
1194*61046927SAndroid Build Coastguard Worker static nir_def*
lower_system_value_to_zero_instr(nir_builder * b,nir_instr * instr,void * _state)1195*61046927SAndroid Build Coastguard Worker lower_system_value_to_zero_instr(nir_builder* b, nir_instr* instr, void* _state)
1196*61046927SAndroid Build Coastguard Worker {
1197*61046927SAndroid Build Coastguard Worker return nir_imm_int(b, 0);
1198*61046927SAndroid Build Coastguard Worker }
1199*61046927SAndroid Build Coastguard Worker
1200*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_system_values_to_zero(nir_shader * shader,gl_system_value * system_values,uint32_t count)1201*61046927SAndroid Build Coastguard Worker dxil_nir_lower_system_values_to_zero(nir_shader* shader,
1202*61046927SAndroid Build Coastguard Worker gl_system_value* system_values,
1203*61046927SAndroid Build Coastguard Worker uint32_t count)
1204*61046927SAndroid Build Coastguard Worker {
1205*61046927SAndroid Build Coastguard Worker zero_system_values_state state = { system_values, count };
1206*61046927SAndroid Build Coastguard Worker return nir_shader_lower_instructions(shader,
1207*61046927SAndroid Build Coastguard Worker lower_system_value_to_zero_filter,
1208*61046927SAndroid Build Coastguard Worker lower_system_value_to_zero_instr,
1209*61046927SAndroid Build Coastguard Worker &state);
1210*61046927SAndroid Build Coastguard Worker }
1211*61046927SAndroid Build Coastguard Worker
1212*61046927SAndroid Build Coastguard Worker static void
lower_load_local_group_size(nir_builder * b,nir_intrinsic_instr * intr)1213*61046927SAndroid Build Coastguard Worker lower_load_local_group_size(nir_builder *b, nir_intrinsic_instr *intr)
1214*61046927SAndroid Build Coastguard Worker {
1215*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(&intr->instr);
1216*61046927SAndroid Build Coastguard Worker
1217*61046927SAndroid Build Coastguard Worker nir_const_value v[3] = {
1218*61046927SAndroid Build Coastguard Worker nir_const_value_for_int(b->shader->info.workgroup_size[0], 32),
1219*61046927SAndroid Build Coastguard Worker nir_const_value_for_int(b->shader->info.workgroup_size[1], 32),
1220*61046927SAndroid Build Coastguard Worker nir_const_value_for_int(b->shader->info.workgroup_size[2], 32)
1221*61046927SAndroid Build Coastguard Worker };
1222*61046927SAndroid Build Coastguard Worker nir_def *size = nir_build_imm(b, 3, 32, v);
1223*61046927SAndroid Build Coastguard Worker nir_def_replace(&intr->def, size);
1224*61046927SAndroid Build Coastguard Worker }
1225*61046927SAndroid Build Coastguard Worker
1226*61046927SAndroid Build Coastguard Worker static bool
lower_system_values_impl(nir_builder * b,nir_intrinsic_instr * intr,void * _state)1227*61046927SAndroid Build Coastguard Worker lower_system_values_impl(nir_builder *b, nir_intrinsic_instr *intr,
1228*61046927SAndroid Build Coastguard Worker void *_state)
1229*61046927SAndroid Build Coastguard Worker {
1230*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
1231*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_workgroup_size:
1232*61046927SAndroid Build Coastguard Worker lower_load_local_group_size(b, intr);
1233*61046927SAndroid Build Coastguard Worker return true;
1234*61046927SAndroid Build Coastguard Worker default:
1235*61046927SAndroid Build Coastguard Worker return false;
1236*61046927SAndroid Build Coastguard Worker }
1237*61046927SAndroid Build Coastguard Worker }
1238*61046927SAndroid Build Coastguard Worker
1239*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_system_values(nir_shader * shader)1240*61046927SAndroid Build Coastguard Worker dxil_nir_lower_system_values(nir_shader *shader)
1241*61046927SAndroid Build Coastguard Worker {
1242*61046927SAndroid Build Coastguard Worker return nir_shader_intrinsics_pass(shader, lower_system_values_impl,
1243*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow | nir_metadata_loop_analysis,
1244*61046927SAndroid Build Coastguard Worker NULL);
1245*61046927SAndroid Build Coastguard Worker }
1246*61046927SAndroid Build Coastguard Worker
1247*61046927SAndroid Build Coastguard Worker static const struct glsl_type *
get_bare_samplers_for_type(const struct glsl_type * type,bool is_shadow)1248*61046927SAndroid Build Coastguard Worker get_bare_samplers_for_type(const struct glsl_type *type, bool is_shadow)
1249*61046927SAndroid Build Coastguard Worker {
1250*61046927SAndroid Build Coastguard Worker const struct glsl_type *base_sampler_type =
1251*61046927SAndroid Build Coastguard Worker is_shadow ?
1252*61046927SAndroid Build Coastguard Worker glsl_bare_shadow_sampler_type() : glsl_bare_sampler_type();
1253*61046927SAndroid Build Coastguard Worker return glsl_type_wrap_in_arrays(base_sampler_type, type);
1254*61046927SAndroid Build Coastguard Worker }
1255*61046927SAndroid Build Coastguard Worker
1256*61046927SAndroid Build Coastguard Worker static const struct glsl_type *
get_textures_for_sampler_type(const struct glsl_type * type)1257*61046927SAndroid Build Coastguard Worker get_textures_for_sampler_type(const struct glsl_type *type)
1258*61046927SAndroid Build Coastguard Worker {
1259*61046927SAndroid Build Coastguard Worker return glsl_type_wrap_in_arrays(
1260*61046927SAndroid Build Coastguard Worker glsl_sampler_type_to_texture(
1261*61046927SAndroid Build Coastguard Worker glsl_without_array(type)), type);
1262*61046927SAndroid Build Coastguard Worker }
1263*61046927SAndroid Build Coastguard Worker
1264*61046927SAndroid Build Coastguard Worker static bool
redirect_sampler_derefs(struct nir_builder * b,nir_instr * instr,void * data)1265*61046927SAndroid Build Coastguard Worker redirect_sampler_derefs(struct nir_builder *b, nir_instr *instr, void *data)
1266*61046927SAndroid Build Coastguard Worker {
1267*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_tex)
1268*61046927SAndroid Build Coastguard Worker return false;
1269*61046927SAndroid Build Coastguard Worker
1270*61046927SAndroid Build Coastguard Worker nir_tex_instr *tex = nir_instr_as_tex(instr);
1271*61046927SAndroid Build Coastguard Worker
1272*61046927SAndroid Build Coastguard Worker int sampler_idx = nir_tex_instr_src_index(tex, nir_tex_src_sampler_deref);
1273*61046927SAndroid Build Coastguard Worker if (sampler_idx == -1) {
1274*61046927SAndroid Build Coastguard Worker /* No sampler deref - does this instruction even need a sampler? If not,
1275*61046927SAndroid Build Coastguard Worker * sampler_index doesn't necessarily point to a sampler, so early-out.
1276*61046927SAndroid Build Coastguard Worker */
1277*61046927SAndroid Build Coastguard Worker if (!nir_tex_instr_need_sampler(tex))
1278*61046927SAndroid Build Coastguard Worker return false;
1279*61046927SAndroid Build Coastguard Worker
1280*61046927SAndroid Build Coastguard Worker /* No derefs but needs a sampler, must be using indices */
1281*61046927SAndroid Build Coastguard Worker nir_variable *bare_sampler = _mesa_hash_table_u64_search(data, tex->sampler_index);
1282*61046927SAndroid Build Coastguard Worker
1283*61046927SAndroid Build Coastguard Worker /* Already have a bare sampler here */
1284*61046927SAndroid Build Coastguard Worker if (bare_sampler)
1285*61046927SAndroid Build Coastguard Worker return false;
1286*61046927SAndroid Build Coastguard Worker
1287*61046927SAndroid Build Coastguard Worker nir_variable *old_sampler = NULL;
1288*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, b->shader, nir_var_uniform) {
1289*61046927SAndroid Build Coastguard Worker if (var->data.binding <= tex->sampler_index &&
1290*61046927SAndroid Build Coastguard Worker var->data.binding + glsl_type_get_sampler_count(var->type) >
1291*61046927SAndroid Build Coastguard Worker tex->sampler_index) {
1292*61046927SAndroid Build Coastguard Worker
1293*61046927SAndroid Build Coastguard Worker /* Already have a bare sampler for this binding and it is of the
1294*61046927SAndroid Build Coastguard Worker * correct type, add it to the table */
1295*61046927SAndroid Build Coastguard Worker if (glsl_type_is_bare_sampler(glsl_without_array(var->type)) &&
1296*61046927SAndroid Build Coastguard Worker glsl_sampler_type_is_shadow(glsl_without_array(var->type)) ==
1297*61046927SAndroid Build Coastguard Worker tex->is_shadow) {
1298*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_insert(data, tex->sampler_index, var);
1299*61046927SAndroid Build Coastguard Worker return false;
1300*61046927SAndroid Build Coastguard Worker }
1301*61046927SAndroid Build Coastguard Worker
1302*61046927SAndroid Build Coastguard Worker old_sampler = var;
1303*61046927SAndroid Build Coastguard Worker }
1304*61046927SAndroid Build Coastguard Worker }
1305*61046927SAndroid Build Coastguard Worker
1306*61046927SAndroid Build Coastguard Worker assert(old_sampler);
1307*61046927SAndroid Build Coastguard Worker
1308*61046927SAndroid Build Coastguard Worker /* Clone the original sampler to a bare sampler of the correct type */
1309*61046927SAndroid Build Coastguard Worker bare_sampler = nir_variable_clone(old_sampler, b->shader);
1310*61046927SAndroid Build Coastguard Worker nir_shader_add_variable(b->shader, bare_sampler);
1311*61046927SAndroid Build Coastguard Worker
1312*61046927SAndroid Build Coastguard Worker bare_sampler->type =
1313*61046927SAndroid Build Coastguard Worker get_bare_samplers_for_type(old_sampler->type, tex->is_shadow);
1314*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_insert(data, tex->sampler_index, bare_sampler);
1315*61046927SAndroid Build Coastguard Worker return true;
1316*61046927SAndroid Build Coastguard Worker }
1317*61046927SAndroid Build Coastguard Worker
1318*61046927SAndroid Build Coastguard Worker /* Using derefs, means we have to rewrite the deref chain in addition to cloning */
1319*61046927SAndroid Build Coastguard Worker nir_deref_instr *final_deref = nir_src_as_deref(tex->src[sampler_idx].src);
1320*61046927SAndroid Build Coastguard Worker nir_deref_path path;
1321*61046927SAndroid Build Coastguard Worker nir_deref_path_init(&path, final_deref, NULL);
1322*61046927SAndroid Build Coastguard Worker
1323*61046927SAndroid Build Coastguard Worker nir_deref_instr *old_tail = path.path[0];
1324*61046927SAndroid Build Coastguard Worker assert(old_tail->deref_type == nir_deref_type_var);
1325*61046927SAndroid Build Coastguard Worker nir_variable *old_var = old_tail->var;
1326*61046927SAndroid Build Coastguard Worker if (glsl_type_is_bare_sampler(glsl_without_array(old_var->type)) &&
1327*61046927SAndroid Build Coastguard Worker glsl_sampler_type_is_shadow(glsl_without_array(old_var->type)) ==
1328*61046927SAndroid Build Coastguard Worker tex->is_shadow) {
1329*61046927SAndroid Build Coastguard Worker nir_deref_path_finish(&path);
1330*61046927SAndroid Build Coastguard Worker return false;
1331*61046927SAndroid Build Coastguard Worker }
1332*61046927SAndroid Build Coastguard Worker
1333*61046927SAndroid Build Coastguard Worker uint64_t var_key = ((uint64_t)old_var->data.descriptor_set << 32) |
1334*61046927SAndroid Build Coastguard Worker old_var->data.binding;
1335*61046927SAndroid Build Coastguard Worker nir_variable *new_var = _mesa_hash_table_u64_search(data, var_key);
1336*61046927SAndroid Build Coastguard Worker if (!new_var) {
1337*61046927SAndroid Build Coastguard Worker new_var = nir_variable_clone(old_var, b->shader);
1338*61046927SAndroid Build Coastguard Worker nir_shader_add_variable(b->shader, new_var);
1339*61046927SAndroid Build Coastguard Worker new_var->type =
1340*61046927SAndroid Build Coastguard Worker get_bare_samplers_for_type(old_var->type, tex->is_shadow);
1341*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_insert(data, var_key, new_var);
1342*61046927SAndroid Build Coastguard Worker }
1343*61046927SAndroid Build Coastguard Worker
1344*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(&old_tail->instr);
1345*61046927SAndroid Build Coastguard Worker nir_deref_instr *new_tail = nir_build_deref_var(b, new_var);
1346*61046927SAndroid Build Coastguard Worker
1347*61046927SAndroid Build Coastguard Worker for (unsigned i = 1; path.path[i]; ++i) {
1348*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(&path.path[i]->instr);
1349*61046927SAndroid Build Coastguard Worker new_tail = nir_build_deref_follower(b, new_tail, path.path[i]);
1350*61046927SAndroid Build Coastguard Worker }
1351*61046927SAndroid Build Coastguard Worker
1352*61046927SAndroid Build Coastguard Worker nir_deref_path_finish(&path);
1353*61046927SAndroid Build Coastguard Worker nir_src_rewrite(&tex->src[sampler_idx].src, &new_tail->def);
1354*61046927SAndroid Build Coastguard Worker return true;
1355*61046927SAndroid Build Coastguard Worker }
1356*61046927SAndroid Build Coastguard Worker
1357*61046927SAndroid Build Coastguard Worker static bool
redirect_texture_derefs(struct nir_builder * b,nir_instr * instr,void * data)1358*61046927SAndroid Build Coastguard Worker redirect_texture_derefs(struct nir_builder *b, nir_instr *instr, void *data)
1359*61046927SAndroid Build Coastguard Worker {
1360*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_tex)
1361*61046927SAndroid Build Coastguard Worker return false;
1362*61046927SAndroid Build Coastguard Worker
1363*61046927SAndroid Build Coastguard Worker nir_tex_instr *tex = nir_instr_as_tex(instr);
1364*61046927SAndroid Build Coastguard Worker
1365*61046927SAndroid Build Coastguard Worker int texture_idx = nir_tex_instr_src_index(tex, nir_tex_src_texture_deref);
1366*61046927SAndroid Build Coastguard Worker if (texture_idx == -1) {
1367*61046927SAndroid Build Coastguard Worker /* No derefs, must be using indices */
1368*61046927SAndroid Build Coastguard Worker nir_variable *bare_sampler = _mesa_hash_table_u64_search(data, tex->texture_index);
1369*61046927SAndroid Build Coastguard Worker
1370*61046927SAndroid Build Coastguard Worker /* Already have a texture here */
1371*61046927SAndroid Build Coastguard Worker if (bare_sampler)
1372*61046927SAndroid Build Coastguard Worker return false;
1373*61046927SAndroid Build Coastguard Worker
1374*61046927SAndroid Build Coastguard Worker nir_variable *typed_sampler = NULL;
1375*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, b->shader, nir_var_uniform) {
1376*61046927SAndroid Build Coastguard Worker if (var->data.binding <= tex->texture_index &&
1377*61046927SAndroid Build Coastguard Worker var->data.binding + glsl_type_get_texture_count(var->type) > tex->texture_index) {
1378*61046927SAndroid Build Coastguard Worker /* Already have a texture for this binding, add it to the table */
1379*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_insert(data, tex->texture_index, var);
1380*61046927SAndroid Build Coastguard Worker return false;
1381*61046927SAndroid Build Coastguard Worker }
1382*61046927SAndroid Build Coastguard Worker
1383*61046927SAndroid Build Coastguard Worker if (var->data.binding <= tex->texture_index &&
1384*61046927SAndroid Build Coastguard Worker var->data.binding + glsl_type_get_sampler_count(var->type) > tex->texture_index &&
1385*61046927SAndroid Build Coastguard Worker !glsl_type_is_bare_sampler(glsl_without_array(var->type))) {
1386*61046927SAndroid Build Coastguard Worker typed_sampler = var;
1387*61046927SAndroid Build Coastguard Worker }
1388*61046927SAndroid Build Coastguard Worker }
1389*61046927SAndroid Build Coastguard Worker
1390*61046927SAndroid Build Coastguard Worker /* Clone the typed sampler to a texture and we're done */
1391*61046927SAndroid Build Coastguard Worker assert(typed_sampler);
1392*61046927SAndroid Build Coastguard Worker bare_sampler = nir_variable_clone(typed_sampler, b->shader);
1393*61046927SAndroid Build Coastguard Worker bare_sampler->type = get_textures_for_sampler_type(typed_sampler->type);
1394*61046927SAndroid Build Coastguard Worker nir_shader_add_variable(b->shader, bare_sampler);
1395*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_insert(data, tex->texture_index, bare_sampler);
1396*61046927SAndroid Build Coastguard Worker return true;
1397*61046927SAndroid Build Coastguard Worker }
1398*61046927SAndroid Build Coastguard Worker
1399*61046927SAndroid Build Coastguard Worker /* Using derefs, means we have to rewrite the deref chain in addition to cloning */
1400*61046927SAndroid Build Coastguard Worker nir_deref_instr *final_deref = nir_src_as_deref(tex->src[texture_idx].src);
1401*61046927SAndroid Build Coastguard Worker nir_deref_path path;
1402*61046927SAndroid Build Coastguard Worker nir_deref_path_init(&path, final_deref, NULL);
1403*61046927SAndroid Build Coastguard Worker
1404*61046927SAndroid Build Coastguard Worker nir_deref_instr *old_tail = path.path[0];
1405*61046927SAndroid Build Coastguard Worker assert(old_tail->deref_type == nir_deref_type_var);
1406*61046927SAndroid Build Coastguard Worker nir_variable *old_var = old_tail->var;
1407*61046927SAndroid Build Coastguard Worker if (glsl_type_is_texture(glsl_without_array(old_var->type)) ||
1408*61046927SAndroid Build Coastguard Worker glsl_type_is_image(glsl_without_array(old_var->type))) {
1409*61046927SAndroid Build Coastguard Worker nir_deref_path_finish(&path);
1410*61046927SAndroid Build Coastguard Worker return false;
1411*61046927SAndroid Build Coastguard Worker }
1412*61046927SAndroid Build Coastguard Worker
1413*61046927SAndroid Build Coastguard Worker uint64_t var_key = ((uint64_t)old_var->data.descriptor_set << 32) |
1414*61046927SAndroid Build Coastguard Worker old_var->data.binding;
1415*61046927SAndroid Build Coastguard Worker nir_variable *new_var = _mesa_hash_table_u64_search(data, var_key);
1416*61046927SAndroid Build Coastguard Worker if (!new_var) {
1417*61046927SAndroid Build Coastguard Worker new_var = nir_variable_clone(old_var, b->shader);
1418*61046927SAndroid Build Coastguard Worker new_var->type = get_textures_for_sampler_type(old_var->type);
1419*61046927SAndroid Build Coastguard Worker nir_shader_add_variable(b->shader, new_var);
1420*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_insert(data, var_key, new_var);
1421*61046927SAndroid Build Coastguard Worker }
1422*61046927SAndroid Build Coastguard Worker
1423*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(&old_tail->instr);
1424*61046927SAndroid Build Coastguard Worker nir_deref_instr *new_tail = nir_build_deref_var(b, new_var);
1425*61046927SAndroid Build Coastguard Worker
1426*61046927SAndroid Build Coastguard Worker for (unsigned i = 1; path.path[i]; ++i) {
1427*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(&path.path[i]->instr);
1428*61046927SAndroid Build Coastguard Worker new_tail = nir_build_deref_follower(b, new_tail, path.path[i]);
1429*61046927SAndroid Build Coastguard Worker }
1430*61046927SAndroid Build Coastguard Worker
1431*61046927SAndroid Build Coastguard Worker nir_deref_path_finish(&path);
1432*61046927SAndroid Build Coastguard Worker nir_src_rewrite(&tex->src[texture_idx].src, &new_tail->def);
1433*61046927SAndroid Build Coastguard Worker
1434*61046927SAndroid Build Coastguard Worker return true;
1435*61046927SAndroid Build Coastguard Worker }
1436*61046927SAndroid Build Coastguard Worker
1437*61046927SAndroid Build Coastguard Worker bool
dxil_nir_split_typed_samplers(nir_shader * nir)1438*61046927SAndroid Build Coastguard Worker dxil_nir_split_typed_samplers(nir_shader *nir)
1439*61046927SAndroid Build Coastguard Worker {
1440*61046927SAndroid Build Coastguard Worker struct hash_table_u64 *hash_table = _mesa_hash_table_u64_create(NULL);
1441*61046927SAndroid Build Coastguard Worker
1442*61046927SAndroid Build Coastguard Worker bool progress = nir_shader_instructions_pass(nir, redirect_sampler_derefs,
1443*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow | nir_metadata_loop_analysis, hash_table);
1444*61046927SAndroid Build Coastguard Worker
1445*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_clear(hash_table);
1446*61046927SAndroid Build Coastguard Worker
1447*61046927SAndroid Build Coastguard Worker progress |= nir_shader_instructions_pass(nir, redirect_texture_derefs,
1448*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow | nir_metadata_loop_analysis, hash_table);
1449*61046927SAndroid Build Coastguard Worker
1450*61046927SAndroid Build Coastguard Worker _mesa_hash_table_u64_destroy(hash_table);
1451*61046927SAndroid Build Coastguard Worker return progress;
1452*61046927SAndroid Build Coastguard Worker }
1453*61046927SAndroid Build Coastguard Worker
1454*61046927SAndroid Build Coastguard Worker
1455*61046927SAndroid Build Coastguard Worker static bool
lower_sysval_to_load_input_impl(nir_builder * b,nir_intrinsic_instr * intr,void * data)1456*61046927SAndroid Build Coastguard Worker lower_sysval_to_load_input_impl(nir_builder *b, nir_intrinsic_instr *intr,
1457*61046927SAndroid Build Coastguard Worker void *data)
1458*61046927SAndroid Build Coastguard Worker {
1459*61046927SAndroid Build Coastguard Worker gl_system_value sysval = SYSTEM_VALUE_MAX;
1460*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
1461*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_instance_id:
1462*61046927SAndroid Build Coastguard Worker sysval = SYSTEM_VALUE_INSTANCE_ID;
1463*61046927SAndroid Build Coastguard Worker break;
1464*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_vertex_id_zero_base:
1465*61046927SAndroid Build Coastguard Worker sysval = SYSTEM_VALUE_VERTEX_ID_ZERO_BASE;
1466*61046927SAndroid Build Coastguard Worker break;
1467*61046927SAndroid Build Coastguard Worker default:
1468*61046927SAndroid Build Coastguard Worker return false;
1469*61046927SAndroid Build Coastguard Worker }
1470*61046927SAndroid Build Coastguard Worker
1471*61046927SAndroid Build Coastguard Worker nir_variable **sysval_vars = (nir_variable **)data;
1472*61046927SAndroid Build Coastguard Worker nir_variable *var = sysval_vars[sysval];
1473*61046927SAndroid Build Coastguard Worker assert(var);
1474*61046927SAndroid Build Coastguard Worker
1475*61046927SAndroid Build Coastguard Worker const nir_alu_type dest_type = nir_get_nir_type_for_glsl_type(var->type);
1476*61046927SAndroid Build Coastguard Worker const unsigned bit_size = intr->def.bit_size;
1477*61046927SAndroid Build Coastguard Worker
1478*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
1479*61046927SAndroid Build Coastguard Worker nir_def *result = nir_load_input(b, intr->def.num_components, bit_size, nir_imm_int(b, 0),
1480*61046927SAndroid Build Coastguard Worker .base = var->data.driver_location, .dest_type = dest_type);
1481*61046927SAndroid Build Coastguard Worker
1482*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&intr->def, result);
1483*61046927SAndroid Build Coastguard Worker return true;
1484*61046927SAndroid Build Coastguard Worker }
1485*61046927SAndroid Build Coastguard Worker
1486*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_sysval_to_load_input(nir_shader * s,nir_variable ** sysval_vars)1487*61046927SAndroid Build Coastguard Worker dxil_nir_lower_sysval_to_load_input(nir_shader *s, nir_variable **sysval_vars)
1488*61046927SAndroid Build Coastguard Worker {
1489*61046927SAndroid Build Coastguard Worker return nir_shader_intrinsics_pass(s, lower_sysval_to_load_input_impl,
1490*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow,
1491*61046927SAndroid Build Coastguard Worker sysval_vars);
1492*61046927SAndroid Build Coastguard Worker }
1493*61046927SAndroid Build Coastguard Worker
1494*61046927SAndroid Build Coastguard Worker /* Comparison function to sort io values so that first come normal varyings,
1495*61046927SAndroid Build Coastguard Worker * then system values, and then system generated values.
1496*61046927SAndroid Build Coastguard Worker */
1497*61046927SAndroid Build Coastguard Worker static int
variable_location_cmp(const nir_variable * a,const nir_variable * b)1498*61046927SAndroid Build Coastguard Worker variable_location_cmp(const nir_variable* a, const nir_variable* b)
1499*61046927SAndroid Build Coastguard Worker {
1500*61046927SAndroid Build Coastguard Worker // Sort by stream, driver_location, location, location_frac, then index
1501*61046927SAndroid Build Coastguard Worker // If all else is equal, sort full vectors before partial ones
1502*61046927SAndroid Build Coastguard Worker unsigned a_location = a->data.location;
1503*61046927SAndroid Build Coastguard Worker if (a_location >= VARYING_SLOT_PATCH0)
1504*61046927SAndroid Build Coastguard Worker a_location -= VARYING_SLOT_PATCH0;
1505*61046927SAndroid Build Coastguard Worker unsigned b_location = b->data.location;
1506*61046927SAndroid Build Coastguard Worker if (b_location >= VARYING_SLOT_PATCH0)
1507*61046927SAndroid Build Coastguard Worker b_location -= VARYING_SLOT_PATCH0;
1508*61046927SAndroid Build Coastguard Worker unsigned a_stream = a->data.stream & ~NIR_STREAM_PACKED;
1509*61046927SAndroid Build Coastguard Worker unsigned b_stream = b->data.stream & ~NIR_STREAM_PACKED;
1510*61046927SAndroid Build Coastguard Worker return a_stream != b_stream ?
1511*61046927SAndroid Build Coastguard Worker a_stream - b_stream :
1512*61046927SAndroid Build Coastguard Worker a->data.driver_location != b->data.driver_location ?
1513*61046927SAndroid Build Coastguard Worker a->data.driver_location - b->data.driver_location :
1514*61046927SAndroid Build Coastguard Worker a_location != b_location ?
1515*61046927SAndroid Build Coastguard Worker a_location - b_location :
1516*61046927SAndroid Build Coastguard Worker a->data.location_frac != b->data.location_frac ?
1517*61046927SAndroid Build Coastguard Worker a->data.location_frac - b->data.location_frac :
1518*61046927SAndroid Build Coastguard Worker a->data.index != b->data.index ?
1519*61046927SAndroid Build Coastguard Worker a->data.index - b->data.index :
1520*61046927SAndroid Build Coastguard Worker glsl_get_component_slots(b->type) - glsl_get_component_slots(a->type);
1521*61046927SAndroid Build Coastguard Worker }
1522*61046927SAndroid Build Coastguard Worker
1523*61046927SAndroid Build Coastguard Worker /* Order varyings according to driver location */
1524*61046927SAndroid Build Coastguard Worker void
dxil_sort_by_driver_location(nir_shader * s,nir_variable_mode modes)1525*61046927SAndroid Build Coastguard Worker dxil_sort_by_driver_location(nir_shader* s, nir_variable_mode modes)
1526*61046927SAndroid Build Coastguard Worker {
1527*61046927SAndroid Build Coastguard Worker nir_sort_variables_with_modes(s, variable_location_cmp, modes);
1528*61046927SAndroid Build Coastguard Worker }
1529*61046927SAndroid Build Coastguard Worker
1530*61046927SAndroid Build Coastguard Worker /* Sort PS outputs so that color outputs come first */
1531*61046927SAndroid Build Coastguard Worker void
dxil_sort_ps_outputs(nir_shader * s)1532*61046927SAndroid Build Coastguard Worker dxil_sort_ps_outputs(nir_shader* s)
1533*61046927SAndroid Build Coastguard Worker {
1534*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes_safe(var, s, nir_var_shader_out) {
1535*61046927SAndroid Build Coastguard Worker /* We use the driver_location here to avoid introducing a new
1536*61046927SAndroid Build Coastguard Worker * struct or member variable here. The true, updated driver location
1537*61046927SAndroid Build Coastguard Worker * will be written below, after sorting */
1538*61046927SAndroid Build Coastguard Worker switch (var->data.location) {
1539*61046927SAndroid Build Coastguard Worker case FRAG_RESULT_DEPTH:
1540*61046927SAndroid Build Coastguard Worker var->data.driver_location = 1;
1541*61046927SAndroid Build Coastguard Worker break;
1542*61046927SAndroid Build Coastguard Worker case FRAG_RESULT_STENCIL:
1543*61046927SAndroid Build Coastguard Worker var->data.driver_location = 2;
1544*61046927SAndroid Build Coastguard Worker break;
1545*61046927SAndroid Build Coastguard Worker case FRAG_RESULT_SAMPLE_MASK:
1546*61046927SAndroid Build Coastguard Worker var->data.driver_location = 3;
1547*61046927SAndroid Build Coastguard Worker break;
1548*61046927SAndroid Build Coastguard Worker default:
1549*61046927SAndroid Build Coastguard Worker var->data.driver_location = 0;
1550*61046927SAndroid Build Coastguard Worker }
1551*61046927SAndroid Build Coastguard Worker }
1552*61046927SAndroid Build Coastguard Worker
1553*61046927SAndroid Build Coastguard Worker nir_sort_variables_with_modes(s, variable_location_cmp,
1554*61046927SAndroid Build Coastguard Worker nir_var_shader_out);
1555*61046927SAndroid Build Coastguard Worker
1556*61046927SAndroid Build Coastguard Worker unsigned driver_loc = 0;
1557*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, s, nir_var_shader_out) {
1558*61046927SAndroid Build Coastguard Worker /* Fractional vars should use the same driver_location as the base. These will
1559*61046927SAndroid Build Coastguard Worker * get fully merged during signature processing.
1560*61046927SAndroid Build Coastguard Worker */
1561*61046927SAndroid Build Coastguard Worker var->data.driver_location = var->data.location_frac ? driver_loc - 1 : driver_loc++;
1562*61046927SAndroid Build Coastguard Worker }
1563*61046927SAndroid Build Coastguard Worker }
1564*61046927SAndroid Build Coastguard Worker
1565*61046927SAndroid Build Coastguard Worker enum dxil_sysvalue_type {
1566*61046927SAndroid Build Coastguard Worker DXIL_NO_SYSVALUE = 0,
1567*61046927SAndroid Build Coastguard Worker DXIL_USED_SYSVALUE,
1568*61046927SAndroid Build Coastguard Worker DXIL_UNUSED_NO_SYSVALUE,
1569*61046927SAndroid Build Coastguard Worker DXIL_SYSVALUE,
1570*61046927SAndroid Build Coastguard Worker DXIL_GENERATED_SYSVALUE,
1571*61046927SAndroid Build Coastguard Worker };
1572*61046927SAndroid Build Coastguard Worker
1573*61046927SAndroid Build Coastguard Worker static enum dxil_sysvalue_type
nir_var_to_dxil_sysvalue_type(nir_variable * var,uint64_t other_stage_mask,const BITSET_WORD * other_stage_frac_mask)1574*61046927SAndroid Build Coastguard Worker nir_var_to_dxil_sysvalue_type(nir_variable *var, uint64_t other_stage_mask,
1575*61046927SAndroid Build Coastguard Worker const BITSET_WORD *other_stage_frac_mask)
1576*61046927SAndroid Build Coastguard Worker {
1577*61046927SAndroid Build Coastguard Worker switch (var->data.location) {
1578*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_FACE:
1579*61046927SAndroid Build Coastguard Worker return DXIL_GENERATED_SYSVALUE;
1580*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_POS:
1581*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_PRIMITIVE_ID:
1582*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_CLIP_DIST0:
1583*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_CLIP_DIST1:
1584*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_PSIZ:
1585*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_TESS_LEVEL_INNER:
1586*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_TESS_LEVEL_OUTER:
1587*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_VIEWPORT:
1588*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_LAYER:
1589*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_VIEW_INDEX:
1590*61046927SAndroid Build Coastguard Worker if (!((1ull << var->data.location) & other_stage_mask))
1591*61046927SAndroid Build Coastguard Worker return DXIL_SYSVALUE;
1592*61046927SAndroid Build Coastguard Worker return DXIL_USED_SYSVALUE;
1593*61046927SAndroid Build Coastguard Worker default:
1594*61046927SAndroid Build Coastguard Worker if (var->data.location < VARYING_SLOT_PATCH0 &&
1595*61046927SAndroid Build Coastguard Worker !((1ull << var->data.location) & other_stage_mask))
1596*61046927SAndroid Build Coastguard Worker return DXIL_UNUSED_NO_SYSVALUE;
1597*61046927SAndroid Build Coastguard Worker if (var->data.location_frac && other_stage_frac_mask &&
1598*61046927SAndroid Build Coastguard Worker var->data.location >= VARYING_SLOT_VAR0 &&
1599*61046927SAndroid Build Coastguard Worker !BITSET_TEST(other_stage_frac_mask, ((var->data.location - VARYING_SLOT_VAR0) * 4 + var->data.location_frac)))
1600*61046927SAndroid Build Coastguard Worker return DXIL_UNUSED_NO_SYSVALUE;
1601*61046927SAndroid Build Coastguard Worker return DXIL_NO_SYSVALUE;
1602*61046927SAndroid Build Coastguard Worker }
1603*61046927SAndroid Build Coastguard Worker }
1604*61046927SAndroid Build Coastguard Worker
1605*61046927SAndroid Build Coastguard Worker /* Order between stage values so that normal varyings come first,
1606*61046927SAndroid Build Coastguard Worker * then sysvalues and then system generated values.
1607*61046927SAndroid Build Coastguard Worker */
1608*61046927SAndroid Build Coastguard Worker void
dxil_reassign_driver_locations(nir_shader * s,nir_variable_mode modes,uint64_t other_stage_mask,const BITSET_WORD * other_stage_frac_mask)1609*61046927SAndroid Build Coastguard Worker dxil_reassign_driver_locations(nir_shader* s, nir_variable_mode modes,
1610*61046927SAndroid Build Coastguard Worker uint64_t other_stage_mask, const BITSET_WORD *other_stage_frac_mask)
1611*61046927SAndroid Build Coastguard Worker {
1612*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes_safe(var, s, modes) {
1613*61046927SAndroid Build Coastguard Worker /* We use the driver_location here to avoid introducing a new
1614*61046927SAndroid Build Coastguard Worker * struct or member variable here. The true, updated driver location
1615*61046927SAndroid Build Coastguard Worker * will be written below, after sorting */
1616*61046927SAndroid Build Coastguard Worker var->data.driver_location = nir_var_to_dxil_sysvalue_type(var, other_stage_mask, other_stage_frac_mask);
1617*61046927SAndroid Build Coastguard Worker }
1618*61046927SAndroid Build Coastguard Worker
1619*61046927SAndroid Build Coastguard Worker nir_sort_variables_with_modes(s, variable_location_cmp, modes);
1620*61046927SAndroid Build Coastguard Worker
1621*61046927SAndroid Build Coastguard Worker unsigned driver_loc = 0, driver_patch_loc = 0;
1622*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, s, modes) {
1623*61046927SAndroid Build Coastguard Worker /* Overlap patches with non-patch */
1624*61046927SAndroid Build Coastguard Worker var->data.driver_location = var->data.patch ?
1625*61046927SAndroid Build Coastguard Worker driver_patch_loc++ : driver_loc++;
1626*61046927SAndroid Build Coastguard Worker }
1627*61046927SAndroid Build Coastguard Worker }
1628*61046927SAndroid Build Coastguard Worker
1629*61046927SAndroid Build Coastguard Worker static bool
lower_ubo_array_one_to_static(struct nir_builder * b,nir_intrinsic_instr * intrin,void * cb_data)1630*61046927SAndroid Build Coastguard Worker lower_ubo_array_one_to_static(struct nir_builder *b,
1631*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intrin,
1632*61046927SAndroid Build Coastguard Worker void *cb_data)
1633*61046927SAndroid Build Coastguard Worker {
1634*61046927SAndroid Build Coastguard Worker if (intrin->intrinsic != nir_intrinsic_load_vulkan_descriptor)
1635*61046927SAndroid Build Coastguard Worker return false;
1636*61046927SAndroid Build Coastguard Worker
1637*61046927SAndroid Build Coastguard Worker nir_variable *var =
1638*61046927SAndroid Build Coastguard Worker nir_get_binding_variable(b->shader, nir_chase_binding(intrin->src[0]));
1639*61046927SAndroid Build Coastguard Worker
1640*61046927SAndroid Build Coastguard Worker if (!var)
1641*61046927SAndroid Build Coastguard Worker return false;
1642*61046927SAndroid Build Coastguard Worker
1643*61046927SAndroid Build Coastguard Worker if (!glsl_type_is_array(var->type) || glsl_array_size(var->type) != 1)
1644*61046927SAndroid Build Coastguard Worker return false;
1645*61046927SAndroid Build Coastguard Worker
1646*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *index = nir_src_as_intrinsic(intrin->src[0]);
1647*61046927SAndroid Build Coastguard Worker /* We currently do not support reindex */
1648*61046927SAndroid Build Coastguard Worker assert(index && index->intrinsic == nir_intrinsic_vulkan_resource_index);
1649*61046927SAndroid Build Coastguard Worker
1650*61046927SAndroid Build Coastguard Worker if (nir_src_is_const(index->src[0]) && nir_src_as_uint(index->src[0]) == 0)
1651*61046927SAndroid Build Coastguard Worker return false;
1652*61046927SAndroid Build Coastguard Worker
1653*61046927SAndroid Build Coastguard Worker if (nir_intrinsic_desc_type(index) != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
1654*61046927SAndroid Build Coastguard Worker return false;
1655*61046927SAndroid Build Coastguard Worker
1656*61046927SAndroid Build Coastguard Worker b->cursor = nir_instr_remove(&index->instr);
1657*61046927SAndroid Build Coastguard Worker
1658*61046927SAndroid Build Coastguard Worker // Indexing out of bounds on array of UBOs is considered undefined
1659*61046927SAndroid Build Coastguard Worker // behavior. Therefore, we just hardcode all the index to 0.
1660*61046927SAndroid Build Coastguard Worker uint8_t bit_size = index->def.bit_size;
1661*61046927SAndroid Build Coastguard Worker nir_def *zero = nir_imm_intN_t(b, 0, bit_size);
1662*61046927SAndroid Build Coastguard Worker nir_def *dest =
1663*61046927SAndroid Build Coastguard Worker nir_vulkan_resource_index(b, index->num_components, bit_size, zero,
1664*61046927SAndroid Build Coastguard Worker .desc_set = nir_intrinsic_desc_set(index),
1665*61046927SAndroid Build Coastguard Worker .binding = nir_intrinsic_binding(index),
1666*61046927SAndroid Build Coastguard Worker .desc_type = nir_intrinsic_desc_type(index));
1667*61046927SAndroid Build Coastguard Worker
1668*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&index->def, dest);
1669*61046927SAndroid Build Coastguard Worker
1670*61046927SAndroid Build Coastguard Worker return true;
1671*61046927SAndroid Build Coastguard Worker }
1672*61046927SAndroid Build Coastguard Worker
1673*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_ubo_array_one_to_static(nir_shader * s)1674*61046927SAndroid Build Coastguard Worker dxil_nir_lower_ubo_array_one_to_static(nir_shader *s)
1675*61046927SAndroid Build Coastguard Worker {
1676*61046927SAndroid Build Coastguard Worker bool progress = nir_shader_intrinsics_pass(s,
1677*61046927SAndroid Build Coastguard Worker lower_ubo_array_one_to_static,
1678*61046927SAndroid Build Coastguard Worker nir_metadata_none, NULL);
1679*61046927SAndroid Build Coastguard Worker
1680*61046927SAndroid Build Coastguard Worker return progress;
1681*61046927SAndroid Build Coastguard Worker }
1682*61046927SAndroid Build Coastguard Worker
1683*61046927SAndroid Build Coastguard Worker static bool
is_fquantize2f16(const nir_instr * instr,const void * data)1684*61046927SAndroid Build Coastguard Worker is_fquantize2f16(const nir_instr *instr, const void *data)
1685*61046927SAndroid Build Coastguard Worker {
1686*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_alu)
1687*61046927SAndroid Build Coastguard Worker return false;
1688*61046927SAndroid Build Coastguard Worker
1689*61046927SAndroid Build Coastguard Worker nir_alu_instr *alu = nir_instr_as_alu(instr);
1690*61046927SAndroid Build Coastguard Worker return alu->op == nir_op_fquantize2f16;
1691*61046927SAndroid Build Coastguard Worker }
1692*61046927SAndroid Build Coastguard Worker
1693*61046927SAndroid Build Coastguard Worker static nir_def *
lower_fquantize2f16(struct nir_builder * b,nir_instr * instr,void * data)1694*61046927SAndroid Build Coastguard Worker lower_fquantize2f16(struct nir_builder *b, nir_instr *instr, void *data)
1695*61046927SAndroid Build Coastguard Worker {
1696*61046927SAndroid Build Coastguard Worker /*
1697*61046927SAndroid Build Coastguard Worker * SpvOpQuantizeToF16 documentation says:
1698*61046927SAndroid Build Coastguard Worker *
1699*61046927SAndroid Build Coastguard Worker * "
1700*61046927SAndroid Build Coastguard Worker * If Value is an infinity, the result is the same infinity.
1701*61046927SAndroid Build Coastguard Worker * If Value is a NaN, the result is a NaN, but not necessarily the same NaN.
1702*61046927SAndroid Build Coastguard Worker * If Value is positive with a magnitude too large to represent as a 16-bit
1703*61046927SAndroid Build Coastguard Worker * floating-point value, the result is positive infinity. If Value is negative
1704*61046927SAndroid Build Coastguard Worker * with a magnitude too large to represent as a 16-bit floating-point value,
1705*61046927SAndroid Build Coastguard Worker * the result is negative infinity. If the magnitude of Value is too small to
1706*61046927SAndroid Build Coastguard Worker * represent as a normalized 16-bit floating-point value, the result may be
1707*61046927SAndroid Build Coastguard Worker * either +0 or -0.
1708*61046927SAndroid Build Coastguard Worker * "
1709*61046927SAndroid Build Coastguard Worker *
1710*61046927SAndroid Build Coastguard Worker * which we turn into:
1711*61046927SAndroid Build Coastguard Worker *
1712*61046927SAndroid Build Coastguard Worker * if (val < MIN_FLOAT16)
1713*61046927SAndroid Build Coastguard Worker * return -INFINITY;
1714*61046927SAndroid Build Coastguard Worker * else if (val > MAX_FLOAT16)
1715*61046927SAndroid Build Coastguard Worker * return -INFINITY;
1716*61046927SAndroid Build Coastguard Worker * else if (fabs(val) < SMALLEST_NORMALIZED_FLOAT16 && sign(val) != 0)
1717*61046927SAndroid Build Coastguard Worker * return -0.0f;
1718*61046927SAndroid Build Coastguard Worker * else if (fabs(val) < SMALLEST_NORMALIZED_FLOAT16 && sign(val) == 0)
1719*61046927SAndroid Build Coastguard Worker * return +0.0f;
1720*61046927SAndroid Build Coastguard Worker * else
1721*61046927SAndroid Build Coastguard Worker * return round(val);
1722*61046927SAndroid Build Coastguard Worker */
1723*61046927SAndroid Build Coastguard Worker nir_alu_instr *alu = nir_instr_as_alu(instr);
1724*61046927SAndroid Build Coastguard Worker nir_def *src =
1725*61046927SAndroid Build Coastguard Worker alu->src[0].src.ssa;
1726*61046927SAndroid Build Coastguard Worker
1727*61046927SAndroid Build Coastguard Worker nir_def *neg_inf_cond =
1728*61046927SAndroid Build Coastguard Worker nir_flt_imm(b, src, -65504.0f);
1729*61046927SAndroid Build Coastguard Worker nir_def *pos_inf_cond =
1730*61046927SAndroid Build Coastguard Worker nir_fgt_imm(b, src, 65504.0f);
1731*61046927SAndroid Build Coastguard Worker nir_def *zero_cond =
1732*61046927SAndroid Build Coastguard Worker nir_flt_imm(b, nir_fabs(b, src), ldexpf(1.0, -14));
1733*61046927SAndroid Build Coastguard Worker nir_def *zero = nir_iand_imm(b, src, 1 << 31);
1734*61046927SAndroid Build Coastguard Worker nir_def *round = nir_iand_imm(b, src, ~BITFIELD_MASK(13));
1735*61046927SAndroid Build Coastguard Worker
1736*61046927SAndroid Build Coastguard Worker nir_def *res =
1737*61046927SAndroid Build Coastguard Worker nir_bcsel(b, neg_inf_cond, nir_imm_float(b, -INFINITY), round);
1738*61046927SAndroid Build Coastguard Worker res = nir_bcsel(b, pos_inf_cond, nir_imm_float(b, INFINITY), res);
1739*61046927SAndroid Build Coastguard Worker res = nir_bcsel(b, zero_cond, zero, res);
1740*61046927SAndroid Build Coastguard Worker return res;
1741*61046927SAndroid Build Coastguard Worker }
1742*61046927SAndroid Build Coastguard Worker
1743*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_fquantize2f16(nir_shader * s)1744*61046927SAndroid Build Coastguard Worker dxil_nir_lower_fquantize2f16(nir_shader *s)
1745*61046927SAndroid Build Coastguard Worker {
1746*61046927SAndroid Build Coastguard Worker return nir_shader_lower_instructions(s, is_fquantize2f16, lower_fquantize2f16, NULL);
1747*61046927SAndroid Build Coastguard Worker }
1748*61046927SAndroid Build Coastguard Worker
1749*61046927SAndroid Build Coastguard Worker static bool
fix_io_uint_deref_types(struct nir_builder * builder,nir_instr * instr,void * data)1750*61046927SAndroid Build Coastguard Worker fix_io_uint_deref_types(struct nir_builder *builder, nir_instr *instr, void *data)
1751*61046927SAndroid Build Coastguard Worker {
1752*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_deref)
1753*61046927SAndroid Build Coastguard Worker return false;
1754*61046927SAndroid Build Coastguard Worker
1755*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_instr_as_deref(instr);
1756*61046927SAndroid Build Coastguard Worker nir_variable *var = nir_deref_instr_get_variable(deref);
1757*61046927SAndroid Build Coastguard Worker
1758*61046927SAndroid Build Coastguard Worker if (var == data) {
1759*61046927SAndroid Build Coastguard Worker deref->type = glsl_type_wrap_in_arrays(glsl_uint_type(), deref->type);
1760*61046927SAndroid Build Coastguard Worker return true;
1761*61046927SAndroid Build Coastguard Worker }
1762*61046927SAndroid Build Coastguard Worker
1763*61046927SAndroid Build Coastguard Worker return false;
1764*61046927SAndroid Build Coastguard Worker }
1765*61046927SAndroid Build Coastguard Worker
1766*61046927SAndroid Build Coastguard Worker static bool
fix_io_uint_type(nir_shader * s,nir_variable_mode modes,int slot)1767*61046927SAndroid Build Coastguard Worker fix_io_uint_type(nir_shader *s, nir_variable_mode modes, int slot)
1768*61046927SAndroid Build Coastguard Worker {
1769*61046927SAndroid Build Coastguard Worker nir_variable *fixed_var = NULL;
1770*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, s, modes) {
1771*61046927SAndroid Build Coastguard Worker if (var->data.location == slot) {
1772*61046927SAndroid Build Coastguard Worker const struct glsl_type *plain_type = glsl_without_array(var->type);
1773*61046927SAndroid Build Coastguard Worker if (plain_type == glsl_uint_type())
1774*61046927SAndroid Build Coastguard Worker return false;
1775*61046927SAndroid Build Coastguard Worker
1776*61046927SAndroid Build Coastguard Worker assert(plain_type == glsl_int_type());
1777*61046927SAndroid Build Coastguard Worker var->type = glsl_type_wrap_in_arrays(glsl_uint_type(), var->type);
1778*61046927SAndroid Build Coastguard Worker fixed_var = var;
1779*61046927SAndroid Build Coastguard Worker break;
1780*61046927SAndroid Build Coastguard Worker }
1781*61046927SAndroid Build Coastguard Worker }
1782*61046927SAndroid Build Coastguard Worker
1783*61046927SAndroid Build Coastguard Worker assert(fixed_var);
1784*61046927SAndroid Build Coastguard Worker
1785*61046927SAndroid Build Coastguard Worker return nir_shader_instructions_pass(s, fix_io_uint_deref_types,
1786*61046927SAndroid Build Coastguard Worker nir_metadata_all, fixed_var);
1787*61046927SAndroid Build Coastguard Worker }
1788*61046927SAndroid Build Coastguard Worker
1789*61046927SAndroid Build Coastguard Worker bool
dxil_nir_fix_io_uint_type(nir_shader * s,uint64_t in_mask,uint64_t out_mask)1790*61046927SAndroid Build Coastguard Worker dxil_nir_fix_io_uint_type(nir_shader *s, uint64_t in_mask, uint64_t out_mask)
1791*61046927SAndroid Build Coastguard Worker {
1792*61046927SAndroid Build Coastguard Worker if (!(s->info.outputs_written & out_mask) &&
1793*61046927SAndroid Build Coastguard Worker !(s->info.inputs_read & in_mask))
1794*61046927SAndroid Build Coastguard Worker return false;
1795*61046927SAndroid Build Coastguard Worker
1796*61046927SAndroid Build Coastguard Worker bool progress = false;
1797*61046927SAndroid Build Coastguard Worker
1798*61046927SAndroid Build Coastguard Worker while (in_mask) {
1799*61046927SAndroid Build Coastguard Worker int slot = u_bit_scan64(&in_mask);
1800*61046927SAndroid Build Coastguard Worker progress |= (s->info.inputs_read & (1ull << slot)) &&
1801*61046927SAndroid Build Coastguard Worker fix_io_uint_type(s, nir_var_shader_in, slot);
1802*61046927SAndroid Build Coastguard Worker }
1803*61046927SAndroid Build Coastguard Worker
1804*61046927SAndroid Build Coastguard Worker while (out_mask) {
1805*61046927SAndroid Build Coastguard Worker int slot = u_bit_scan64(&out_mask);
1806*61046927SAndroid Build Coastguard Worker progress |= (s->info.outputs_written & (1ull << slot)) &&
1807*61046927SAndroid Build Coastguard Worker fix_io_uint_type(s, nir_var_shader_out, slot);
1808*61046927SAndroid Build Coastguard Worker }
1809*61046927SAndroid Build Coastguard Worker
1810*61046927SAndroid Build Coastguard Worker return progress;
1811*61046927SAndroid Build Coastguard Worker }
1812*61046927SAndroid Build Coastguard Worker
1813*61046927SAndroid Build Coastguard Worker static bool
lower_kill(struct nir_builder * builder,nir_intrinsic_instr * intr,void * _cb_data)1814*61046927SAndroid Build Coastguard Worker lower_kill(struct nir_builder *builder, nir_intrinsic_instr *intr,
1815*61046927SAndroid Build Coastguard Worker void *_cb_data)
1816*61046927SAndroid Build Coastguard Worker {
1817*61046927SAndroid Build Coastguard Worker if (intr->intrinsic != nir_intrinsic_terminate &&
1818*61046927SAndroid Build Coastguard Worker intr->intrinsic != nir_intrinsic_terminate_if)
1819*61046927SAndroid Build Coastguard Worker return false;
1820*61046927SAndroid Build Coastguard Worker
1821*61046927SAndroid Build Coastguard Worker builder->cursor = nir_instr_remove(&intr->instr);
1822*61046927SAndroid Build Coastguard Worker nir_def *condition;
1823*61046927SAndroid Build Coastguard Worker
1824*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_terminate) {
1825*61046927SAndroid Build Coastguard Worker nir_demote(builder);
1826*61046927SAndroid Build Coastguard Worker condition = nir_imm_true(builder);
1827*61046927SAndroid Build Coastguard Worker } else {
1828*61046927SAndroid Build Coastguard Worker nir_demote_if(builder, intr->src[0].ssa);
1829*61046927SAndroid Build Coastguard Worker condition = intr->src[0].ssa;
1830*61046927SAndroid Build Coastguard Worker }
1831*61046927SAndroid Build Coastguard Worker
1832*61046927SAndroid Build Coastguard Worker /* Create a new block by branching on the discard condition so that this return
1833*61046927SAndroid Build Coastguard Worker * is definitely the last instruction in its own block */
1834*61046927SAndroid Build Coastguard Worker nir_if *nif = nir_push_if(builder, condition);
1835*61046927SAndroid Build Coastguard Worker nir_jump(builder, nir_jump_return);
1836*61046927SAndroid Build Coastguard Worker nir_pop_if(builder, nif);
1837*61046927SAndroid Build Coastguard Worker
1838*61046927SAndroid Build Coastguard Worker return true;
1839*61046927SAndroid Build Coastguard Worker }
1840*61046927SAndroid Build Coastguard Worker
1841*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_discard_and_terminate(nir_shader * s)1842*61046927SAndroid Build Coastguard Worker dxil_nir_lower_discard_and_terminate(nir_shader *s)
1843*61046927SAndroid Build Coastguard Worker {
1844*61046927SAndroid Build Coastguard Worker if (s->info.stage != MESA_SHADER_FRAGMENT)
1845*61046927SAndroid Build Coastguard Worker return false;
1846*61046927SAndroid Build Coastguard Worker
1847*61046927SAndroid Build Coastguard Worker // This pass only works if all functions have been inlined
1848*61046927SAndroid Build Coastguard Worker assert(exec_list_length(&s->functions) == 1);
1849*61046927SAndroid Build Coastguard Worker return nir_shader_intrinsics_pass(s, lower_kill, nir_metadata_none, NULL);
1850*61046927SAndroid Build Coastguard Worker }
1851*61046927SAndroid Build Coastguard Worker
1852*61046927SAndroid Build Coastguard Worker static bool
update_writes(struct nir_builder * b,nir_intrinsic_instr * intr,void * _state)1853*61046927SAndroid Build Coastguard Worker update_writes(struct nir_builder *b, nir_intrinsic_instr *intr, void *_state)
1854*61046927SAndroid Build Coastguard Worker {
1855*61046927SAndroid Build Coastguard Worker if (intr->intrinsic != nir_intrinsic_store_output)
1856*61046927SAndroid Build Coastguard Worker return false;
1857*61046927SAndroid Build Coastguard Worker
1858*61046927SAndroid Build Coastguard Worker nir_io_semantics io = nir_intrinsic_io_semantics(intr);
1859*61046927SAndroid Build Coastguard Worker if (io.location != VARYING_SLOT_POS)
1860*61046927SAndroid Build Coastguard Worker return false;
1861*61046927SAndroid Build Coastguard Worker
1862*61046927SAndroid Build Coastguard Worker nir_def *src = intr->src[0].ssa;
1863*61046927SAndroid Build Coastguard Worker unsigned write_mask = nir_intrinsic_write_mask(intr);
1864*61046927SAndroid Build Coastguard Worker if (src->num_components == 4 && write_mask == 0xf)
1865*61046927SAndroid Build Coastguard Worker return false;
1866*61046927SAndroid Build Coastguard Worker
1867*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
1868*61046927SAndroid Build Coastguard Worker unsigned first_comp = nir_intrinsic_component(intr);
1869*61046927SAndroid Build Coastguard Worker nir_def *channels[4] = { NULL, NULL, NULL, NULL };
1870*61046927SAndroid Build Coastguard Worker assert(first_comp + src->num_components <= ARRAY_SIZE(channels));
1871*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < src->num_components; ++i)
1872*61046927SAndroid Build Coastguard Worker if (write_mask & (1 << i))
1873*61046927SAndroid Build Coastguard Worker channels[i + first_comp] = nir_channel(b, src, i);
1874*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < 4; ++i)
1875*61046927SAndroid Build Coastguard Worker if (!channels[i])
1876*61046927SAndroid Build Coastguard Worker channels[i] = nir_imm_intN_t(b, 0, src->bit_size);
1877*61046927SAndroid Build Coastguard Worker
1878*61046927SAndroid Build Coastguard Worker intr->num_components = 4;
1879*61046927SAndroid Build Coastguard Worker nir_src_rewrite(&intr->src[0], nir_vec(b, channels, 4));
1880*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_component(intr, 0);
1881*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_write_mask(intr, 0xf);
1882*61046927SAndroid Build Coastguard Worker return true;
1883*61046927SAndroid Build Coastguard Worker }
1884*61046927SAndroid Build Coastguard Worker
1885*61046927SAndroid Build Coastguard Worker bool
dxil_nir_ensure_position_writes(nir_shader * s)1886*61046927SAndroid Build Coastguard Worker dxil_nir_ensure_position_writes(nir_shader *s)
1887*61046927SAndroid Build Coastguard Worker {
1888*61046927SAndroid Build Coastguard Worker if (s->info.stage != MESA_SHADER_VERTEX &&
1889*61046927SAndroid Build Coastguard Worker s->info.stage != MESA_SHADER_GEOMETRY &&
1890*61046927SAndroid Build Coastguard Worker s->info.stage != MESA_SHADER_TESS_EVAL)
1891*61046927SAndroid Build Coastguard Worker return false;
1892*61046927SAndroid Build Coastguard Worker if ((s->info.outputs_written & VARYING_BIT_POS) == 0)
1893*61046927SAndroid Build Coastguard Worker return false;
1894*61046927SAndroid Build Coastguard Worker
1895*61046927SAndroid Build Coastguard Worker return nir_shader_intrinsics_pass(s, update_writes,
1896*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow,
1897*61046927SAndroid Build Coastguard Worker NULL);
1898*61046927SAndroid Build Coastguard Worker }
1899*61046927SAndroid Build Coastguard Worker
1900*61046927SAndroid Build Coastguard Worker static bool
is_sample_pos(const nir_instr * instr,const void * _data)1901*61046927SAndroid Build Coastguard Worker is_sample_pos(const nir_instr *instr, const void *_data)
1902*61046927SAndroid Build Coastguard Worker {
1903*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_intrinsic)
1904*61046927SAndroid Build Coastguard Worker return false;
1905*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
1906*61046927SAndroid Build Coastguard Worker return intr->intrinsic == nir_intrinsic_load_sample_pos;
1907*61046927SAndroid Build Coastguard Worker }
1908*61046927SAndroid Build Coastguard Worker
1909*61046927SAndroid Build Coastguard Worker static nir_def *
lower_sample_pos(nir_builder * b,nir_instr * instr,void * _data)1910*61046927SAndroid Build Coastguard Worker lower_sample_pos(nir_builder *b, nir_instr *instr, void *_data)
1911*61046927SAndroid Build Coastguard Worker {
1912*61046927SAndroid Build Coastguard Worker return nir_load_sample_pos_from_id(b, 32, nir_load_sample_id(b));
1913*61046927SAndroid Build Coastguard Worker }
1914*61046927SAndroid Build Coastguard Worker
1915*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_sample_pos(nir_shader * s)1916*61046927SAndroid Build Coastguard Worker dxil_nir_lower_sample_pos(nir_shader *s)
1917*61046927SAndroid Build Coastguard Worker {
1918*61046927SAndroid Build Coastguard Worker return nir_shader_lower_instructions(s, is_sample_pos, lower_sample_pos, NULL);
1919*61046927SAndroid Build Coastguard Worker }
1920*61046927SAndroid Build Coastguard Worker
1921*61046927SAndroid Build Coastguard Worker static bool
lower_subgroup_id(nir_builder * b,nir_intrinsic_instr * intr,void * data)1922*61046927SAndroid Build Coastguard Worker lower_subgroup_id(nir_builder *b, nir_intrinsic_instr *intr, void *data)
1923*61046927SAndroid Build Coastguard Worker {
1924*61046927SAndroid Build Coastguard Worker if (intr->intrinsic != nir_intrinsic_load_subgroup_id)
1925*61046927SAndroid Build Coastguard Worker return false;
1926*61046927SAndroid Build Coastguard Worker
1927*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_impl(b->impl);
1928*61046927SAndroid Build Coastguard Worker if (b->shader->info.stage == MESA_SHADER_COMPUTE &&
1929*61046927SAndroid Build Coastguard Worker b->shader->info.workgroup_size[1] == 1 &&
1930*61046927SAndroid Build Coastguard Worker b->shader->info.workgroup_size[2] == 1) {
1931*61046927SAndroid Build Coastguard Worker /* When using Nx1x1 groups, use a simple stable algorithm
1932*61046927SAndroid Build Coastguard Worker * which is almost guaranteed to be correct. */
1933*61046927SAndroid Build Coastguard Worker nir_def *subgroup_id = nir_udiv(b, nir_load_local_invocation_index(b), nir_load_subgroup_size(b));
1934*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&intr->def, subgroup_id);
1935*61046927SAndroid Build Coastguard Worker return true;
1936*61046927SAndroid Build Coastguard Worker }
1937*61046927SAndroid Build Coastguard Worker
1938*61046927SAndroid Build Coastguard Worker nir_def **subgroup_id = (nir_def **)data;
1939*61046927SAndroid Build Coastguard Worker if (*subgroup_id == NULL) {
1940*61046927SAndroid Build Coastguard Worker nir_variable *subgroup_id_counter = nir_variable_create(b->shader, nir_var_mem_shared, glsl_uint_type(), "dxil_SubgroupID_counter");
1941*61046927SAndroid Build Coastguard Worker nir_variable *subgroup_id_local = nir_local_variable_create(b->impl, glsl_uint_type(), "dxil_SubgroupID_local");
1942*61046927SAndroid Build Coastguard Worker nir_store_var(b, subgroup_id_local, nir_imm_int(b, 0), 1);
1943*61046927SAndroid Build Coastguard Worker
1944*61046927SAndroid Build Coastguard Worker nir_deref_instr *counter_deref = nir_build_deref_var(b, subgroup_id_counter);
1945*61046927SAndroid Build Coastguard Worker nir_def *tid = nir_load_local_invocation_index(b);
1946*61046927SAndroid Build Coastguard Worker nir_if *nif = nir_push_if(b, nir_ieq_imm(b, tid, 0));
1947*61046927SAndroid Build Coastguard Worker nir_store_deref(b, counter_deref, nir_imm_int(b, 0), 1);
1948*61046927SAndroid Build Coastguard Worker nir_pop_if(b, nif);
1949*61046927SAndroid Build Coastguard Worker
1950*61046927SAndroid Build Coastguard Worker nir_barrier(b,
1951*61046927SAndroid Build Coastguard Worker .execution_scope = SCOPE_WORKGROUP,
1952*61046927SAndroid Build Coastguard Worker .memory_scope = SCOPE_WORKGROUP,
1953*61046927SAndroid Build Coastguard Worker .memory_semantics = NIR_MEMORY_ACQ_REL,
1954*61046927SAndroid Build Coastguard Worker .memory_modes = nir_var_mem_shared);
1955*61046927SAndroid Build Coastguard Worker
1956*61046927SAndroid Build Coastguard Worker nif = nir_push_if(b, nir_elect(b, 1));
1957*61046927SAndroid Build Coastguard Worker nir_def *subgroup_id_first_thread = nir_deref_atomic(b, 32, &counter_deref->def, nir_imm_int(b, 1),
1958*61046927SAndroid Build Coastguard Worker .atomic_op = nir_atomic_op_iadd);
1959*61046927SAndroid Build Coastguard Worker nir_store_var(b, subgroup_id_local, subgroup_id_first_thread, 1);
1960*61046927SAndroid Build Coastguard Worker nir_pop_if(b, nif);
1961*61046927SAndroid Build Coastguard Worker
1962*61046927SAndroid Build Coastguard Worker nir_def *subgroup_id_loaded = nir_load_var(b, subgroup_id_local);
1963*61046927SAndroid Build Coastguard Worker *subgroup_id = nir_read_first_invocation(b, subgroup_id_loaded);
1964*61046927SAndroid Build Coastguard Worker }
1965*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&intr->def, *subgroup_id);
1966*61046927SAndroid Build Coastguard Worker return true;
1967*61046927SAndroid Build Coastguard Worker }
1968*61046927SAndroid Build Coastguard Worker
1969*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_subgroup_id(nir_shader * s)1970*61046927SAndroid Build Coastguard Worker dxil_nir_lower_subgroup_id(nir_shader *s)
1971*61046927SAndroid Build Coastguard Worker {
1972*61046927SAndroid Build Coastguard Worker nir_def *subgroup_id = NULL;
1973*61046927SAndroid Build Coastguard Worker return nir_shader_intrinsics_pass(s, lower_subgroup_id, nir_metadata_none,
1974*61046927SAndroid Build Coastguard Worker &subgroup_id);
1975*61046927SAndroid Build Coastguard Worker }
1976*61046927SAndroid Build Coastguard Worker
1977*61046927SAndroid Build Coastguard Worker static bool
lower_num_subgroups(nir_builder * b,nir_intrinsic_instr * intr,void * data)1978*61046927SAndroid Build Coastguard Worker lower_num_subgroups(nir_builder *b, nir_intrinsic_instr *intr, void *data)
1979*61046927SAndroid Build Coastguard Worker {
1980*61046927SAndroid Build Coastguard Worker if (intr->intrinsic != nir_intrinsic_load_num_subgroups)
1981*61046927SAndroid Build Coastguard Worker return false;
1982*61046927SAndroid Build Coastguard Worker
1983*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
1984*61046927SAndroid Build Coastguard Worker nir_def *subgroup_size = nir_load_subgroup_size(b);
1985*61046927SAndroid Build Coastguard Worker nir_def *size_minus_one = nir_iadd_imm(b, subgroup_size, -1);
1986*61046927SAndroid Build Coastguard Worker nir_def *workgroup_size_vec = nir_load_workgroup_size(b);
1987*61046927SAndroid Build Coastguard Worker nir_def *workgroup_size = nir_imul(b, nir_channel(b, workgroup_size_vec, 0),
1988*61046927SAndroid Build Coastguard Worker nir_imul(b, nir_channel(b, workgroup_size_vec, 1),
1989*61046927SAndroid Build Coastguard Worker nir_channel(b, workgroup_size_vec, 2)));
1990*61046927SAndroid Build Coastguard Worker nir_def *ret = nir_idiv(b, nir_iadd(b, workgroup_size, size_minus_one), subgroup_size);
1991*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&intr->def, ret);
1992*61046927SAndroid Build Coastguard Worker return true;
1993*61046927SAndroid Build Coastguard Worker }
1994*61046927SAndroid Build Coastguard Worker
1995*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_num_subgroups(nir_shader * s)1996*61046927SAndroid Build Coastguard Worker dxil_nir_lower_num_subgroups(nir_shader *s)
1997*61046927SAndroid Build Coastguard Worker {
1998*61046927SAndroid Build Coastguard Worker return nir_shader_intrinsics_pass(s, lower_num_subgroups,
1999*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow |
2000*61046927SAndroid Build Coastguard Worker nir_metadata_loop_analysis, NULL);
2001*61046927SAndroid Build Coastguard Worker }
2002*61046927SAndroid Build Coastguard Worker
2003*61046927SAndroid Build Coastguard Worker
2004*61046927SAndroid Build Coastguard Worker static const struct glsl_type *
get_cast_type(unsigned bit_size)2005*61046927SAndroid Build Coastguard Worker get_cast_type(unsigned bit_size)
2006*61046927SAndroid Build Coastguard Worker {
2007*61046927SAndroid Build Coastguard Worker switch (bit_size) {
2008*61046927SAndroid Build Coastguard Worker case 64:
2009*61046927SAndroid Build Coastguard Worker return glsl_int64_t_type();
2010*61046927SAndroid Build Coastguard Worker case 32:
2011*61046927SAndroid Build Coastguard Worker return glsl_int_type();
2012*61046927SAndroid Build Coastguard Worker case 16:
2013*61046927SAndroid Build Coastguard Worker return glsl_int16_t_type();
2014*61046927SAndroid Build Coastguard Worker case 8:
2015*61046927SAndroid Build Coastguard Worker return glsl_int8_t_type();
2016*61046927SAndroid Build Coastguard Worker }
2017*61046927SAndroid Build Coastguard Worker unreachable("Invalid bit_size");
2018*61046927SAndroid Build Coastguard Worker }
2019*61046927SAndroid Build Coastguard Worker
2020*61046927SAndroid Build Coastguard Worker static void
split_unaligned_load(nir_builder * b,nir_intrinsic_instr * intrin,unsigned alignment)2021*61046927SAndroid Build Coastguard Worker split_unaligned_load(nir_builder *b, nir_intrinsic_instr *intrin, unsigned alignment)
2022*61046927SAndroid Build Coastguard Worker {
2023*61046927SAndroid Build Coastguard Worker enum gl_access_qualifier access = nir_intrinsic_access(intrin);
2024*61046927SAndroid Build Coastguard Worker nir_def *srcs[NIR_MAX_VEC_COMPONENTS * NIR_MAX_VEC_COMPONENTS * sizeof(int64_t) / 8];
2025*61046927SAndroid Build Coastguard Worker unsigned comp_size = intrin->def.bit_size / 8;
2026*61046927SAndroid Build Coastguard Worker unsigned num_comps = intrin->def.num_components;
2027*61046927SAndroid Build Coastguard Worker
2028*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intrin->instr);
2029*61046927SAndroid Build Coastguard Worker
2030*61046927SAndroid Build Coastguard Worker nir_deref_instr *ptr = nir_src_as_deref(intrin->src[0]);
2031*61046927SAndroid Build Coastguard Worker
2032*61046927SAndroid Build Coastguard Worker const struct glsl_type *cast_type = get_cast_type(alignment * 8);
2033*61046927SAndroid Build Coastguard Worker nir_deref_instr *cast = nir_build_deref_cast(b, &ptr->def, ptr->modes, cast_type, alignment);
2034*61046927SAndroid Build Coastguard Worker
2035*61046927SAndroid Build Coastguard Worker unsigned num_loads = DIV_ROUND_UP(comp_size * num_comps, alignment);
2036*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_loads; ++i) {
2037*61046927SAndroid Build Coastguard Worker nir_deref_instr *elem = nir_build_deref_ptr_as_array(b, cast, nir_imm_intN_t(b, i, cast->def.bit_size));
2038*61046927SAndroid Build Coastguard Worker srcs[i] = nir_load_deref_with_access(b, elem, access);
2039*61046927SAndroid Build Coastguard Worker }
2040*61046927SAndroid Build Coastguard Worker
2041*61046927SAndroid Build Coastguard Worker nir_def *new_dest = nir_extract_bits(b, srcs, num_loads, 0, num_comps, intrin->def.bit_size);
2042*61046927SAndroid Build Coastguard Worker nir_def_replace(&intrin->def, new_dest);
2043*61046927SAndroid Build Coastguard Worker }
2044*61046927SAndroid Build Coastguard Worker
2045*61046927SAndroid Build Coastguard Worker static void
split_unaligned_store(nir_builder * b,nir_intrinsic_instr * intrin,unsigned alignment)2046*61046927SAndroid Build Coastguard Worker split_unaligned_store(nir_builder *b, nir_intrinsic_instr *intrin, unsigned alignment)
2047*61046927SAndroid Build Coastguard Worker {
2048*61046927SAndroid Build Coastguard Worker enum gl_access_qualifier access = nir_intrinsic_access(intrin);
2049*61046927SAndroid Build Coastguard Worker
2050*61046927SAndroid Build Coastguard Worker nir_def *value = intrin->src[1].ssa;
2051*61046927SAndroid Build Coastguard Worker unsigned comp_size = value->bit_size / 8;
2052*61046927SAndroid Build Coastguard Worker unsigned num_comps = value->num_components;
2053*61046927SAndroid Build Coastguard Worker
2054*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intrin->instr);
2055*61046927SAndroid Build Coastguard Worker
2056*61046927SAndroid Build Coastguard Worker nir_deref_instr *ptr = nir_src_as_deref(intrin->src[0]);
2057*61046927SAndroid Build Coastguard Worker
2058*61046927SAndroid Build Coastguard Worker const struct glsl_type *cast_type = get_cast_type(alignment * 8);
2059*61046927SAndroid Build Coastguard Worker nir_deref_instr *cast = nir_build_deref_cast(b, &ptr->def, ptr->modes, cast_type, alignment);
2060*61046927SAndroid Build Coastguard Worker
2061*61046927SAndroid Build Coastguard Worker unsigned num_stores = DIV_ROUND_UP(comp_size * num_comps, alignment);
2062*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_stores; ++i) {
2063*61046927SAndroid Build Coastguard Worker nir_def *substore_val = nir_extract_bits(b, &value, 1, i * alignment * 8, 1, alignment * 8);
2064*61046927SAndroid Build Coastguard Worker nir_deref_instr *elem = nir_build_deref_ptr_as_array(b, cast, nir_imm_intN_t(b, i, cast->def.bit_size));
2065*61046927SAndroid Build Coastguard Worker nir_store_deref_with_access(b, elem, substore_val, ~0, access);
2066*61046927SAndroid Build Coastguard Worker }
2067*61046927SAndroid Build Coastguard Worker
2068*61046927SAndroid Build Coastguard Worker nir_instr_remove(&intrin->instr);
2069*61046927SAndroid Build Coastguard Worker }
2070*61046927SAndroid Build Coastguard Worker
2071*61046927SAndroid Build Coastguard Worker bool
dxil_nir_split_unaligned_loads_stores(nir_shader * shader,nir_variable_mode modes)2072*61046927SAndroid Build Coastguard Worker dxil_nir_split_unaligned_loads_stores(nir_shader *shader, nir_variable_mode modes)
2073*61046927SAndroid Build Coastguard Worker {
2074*61046927SAndroid Build Coastguard Worker bool progress = false;
2075*61046927SAndroid Build Coastguard Worker
2076*61046927SAndroid Build Coastguard Worker nir_foreach_function_impl(impl, shader) {
2077*61046927SAndroid Build Coastguard Worker nir_builder b = nir_builder_create(impl);
2078*61046927SAndroid Build Coastguard Worker
2079*61046927SAndroid Build Coastguard Worker nir_foreach_block(block, impl) {
2080*61046927SAndroid Build Coastguard Worker nir_foreach_instr_safe(instr, block) {
2081*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_intrinsic)
2082*61046927SAndroid Build Coastguard Worker continue;
2083*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
2084*61046927SAndroid Build Coastguard Worker if (intrin->intrinsic != nir_intrinsic_load_deref &&
2085*61046927SAndroid Build Coastguard Worker intrin->intrinsic != nir_intrinsic_store_deref)
2086*61046927SAndroid Build Coastguard Worker continue;
2087*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
2088*61046927SAndroid Build Coastguard Worker if (!nir_deref_mode_may_be(deref, modes))
2089*61046927SAndroid Build Coastguard Worker continue;
2090*61046927SAndroid Build Coastguard Worker
2091*61046927SAndroid Build Coastguard Worker unsigned align_mul = 0, align_offset = 0;
2092*61046927SAndroid Build Coastguard Worker nir_get_explicit_deref_align(deref, true, &align_mul, &align_offset);
2093*61046927SAndroid Build Coastguard Worker
2094*61046927SAndroid Build Coastguard Worker unsigned alignment = align_offset ? 1 << (ffs(align_offset) - 1) : align_mul;
2095*61046927SAndroid Build Coastguard Worker
2096*61046927SAndroid Build Coastguard Worker /* We can load anything at 4-byte alignment, except for
2097*61046927SAndroid Build Coastguard Worker * UBOs (AKA CBs where the granularity is 16 bytes).
2098*61046927SAndroid Build Coastguard Worker */
2099*61046927SAndroid Build Coastguard Worker unsigned req_align = (nir_deref_mode_is_one_of(deref, nir_var_mem_ubo | nir_var_mem_push_const) ? 16 : 4);
2100*61046927SAndroid Build Coastguard Worker if (alignment >= req_align)
2101*61046927SAndroid Build Coastguard Worker continue;
2102*61046927SAndroid Build Coastguard Worker
2103*61046927SAndroid Build Coastguard Worker nir_def *val;
2104*61046927SAndroid Build Coastguard Worker if (intrin->intrinsic == nir_intrinsic_load_deref) {
2105*61046927SAndroid Build Coastguard Worker val = &intrin->def;
2106*61046927SAndroid Build Coastguard Worker } else {
2107*61046927SAndroid Build Coastguard Worker val = intrin->src[1].ssa;
2108*61046927SAndroid Build Coastguard Worker }
2109*61046927SAndroid Build Coastguard Worker
2110*61046927SAndroid Build Coastguard Worker unsigned scalar_byte_size = glsl_type_is_boolean(deref->type) ? 4 : glsl_get_bit_size(deref->type) / 8;
2111*61046927SAndroid Build Coastguard Worker unsigned num_components =
2112*61046927SAndroid Build Coastguard Worker /* If the vector stride is larger than the scalar size, lower_explicit_io will
2113*61046927SAndroid Build Coastguard Worker * turn this into multiple scalar loads anyway, so we don't have to split it here. */
2114*61046927SAndroid Build Coastguard Worker glsl_get_explicit_stride(deref->type) > scalar_byte_size ? 1 :
2115*61046927SAndroid Build Coastguard Worker (val->num_components == 3 ? 4 : val->num_components);
2116*61046927SAndroid Build Coastguard Worker unsigned natural_alignment = scalar_byte_size * num_components;
2117*61046927SAndroid Build Coastguard Worker
2118*61046927SAndroid Build Coastguard Worker if (alignment >= natural_alignment)
2119*61046927SAndroid Build Coastguard Worker continue;
2120*61046927SAndroid Build Coastguard Worker
2121*61046927SAndroid Build Coastguard Worker if (intrin->intrinsic == nir_intrinsic_load_deref)
2122*61046927SAndroid Build Coastguard Worker split_unaligned_load(&b, intrin, alignment);
2123*61046927SAndroid Build Coastguard Worker else
2124*61046927SAndroid Build Coastguard Worker split_unaligned_store(&b, intrin, alignment);
2125*61046927SAndroid Build Coastguard Worker progress = true;
2126*61046927SAndroid Build Coastguard Worker }
2127*61046927SAndroid Build Coastguard Worker }
2128*61046927SAndroid Build Coastguard Worker }
2129*61046927SAndroid Build Coastguard Worker
2130*61046927SAndroid Build Coastguard Worker return progress;
2131*61046927SAndroid Build Coastguard Worker }
2132*61046927SAndroid Build Coastguard Worker
2133*61046927SAndroid Build Coastguard Worker static void
lower_inclusive_to_exclusive(nir_builder * b,nir_intrinsic_instr * intr)2134*61046927SAndroid Build Coastguard Worker lower_inclusive_to_exclusive(nir_builder *b, nir_intrinsic_instr *intr)
2135*61046927SAndroid Build Coastguard Worker {
2136*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(&intr->instr);
2137*61046927SAndroid Build Coastguard Worker
2138*61046927SAndroid Build Coastguard Worker nir_op op = nir_intrinsic_reduction_op(intr);
2139*61046927SAndroid Build Coastguard Worker intr->intrinsic = nir_intrinsic_exclusive_scan;
2140*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_reduction_op(intr, op);
2141*61046927SAndroid Build Coastguard Worker
2142*61046927SAndroid Build Coastguard Worker nir_def *final_val = nir_build_alu2(b, nir_intrinsic_reduction_op(intr),
2143*61046927SAndroid Build Coastguard Worker &intr->def, intr->src[0].ssa);
2144*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses_after(&intr->def, final_val, final_val->parent_instr);
2145*61046927SAndroid Build Coastguard Worker }
2146*61046927SAndroid Build Coastguard Worker
2147*61046927SAndroid Build Coastguard Worker static bool
lower_subgroup_scan(nir_builder * b,nir_intrinsic_instr * intr,void * data)2148*61046927SAndroid Build Coastguard Worker lower_subgroup_scan(nir_builder *b, nir_intrinsic_instr *intr, void *data)
2149*61046927SAndroid Build Coastguard Worker {
2150*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
2151*61046927SAndroid Build Coastguard Worker case nir_intrinsic_exclusive_scan:
2152*61046927SAndroid Build Coastguard Worker case nir_intrinsic_inclusive_scan:
2153*61046927SAndroid Build Coastguard Worker switch ((nir_op)nir_intrinsic_reduction_op(intr)) {
2154*61046927SAndroid Build Coastguard Worker case nir_op_iadd:
2155*61046927SAndroid Build Coastguard Worker case nir_op_fadd:
2156*61046927SAndroid Build Coastguard Worker case nir_op_imul:
2157*61046927SAndroid Build Coastguard Worker case nir_op_fmul:
2158*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_exclusive_scan)
2159*61046927SAndroid Build Coastguard Worker return false;
2160*61046927SAndroid Build Coastguard Worker lower_inclusive_to_exclusive(b, intr);
2161*61046927SAndroid Build Coastguard Worker return true;
2162*61046927SAndroid Build Coastguard Worker default:
2163*61046927SAndroid Build Coastguard Worker break;
2164*61046927SAndroid Build Coastguard Worker }
2165*61046927SAndroid Build Coastguard Worker break;
2166*61046927SAndroid Build Coastguard Worker default:
2167*61046927SAndroid Build Coastguard Worker return false;
2168*61046927SAndroid Build Coastguard Worker }
2169*61046927SAndroid Build Coastguard Worker
2170*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
2171*61046927SAndroid Build Coastguard Worker nir_op op = nir_intrinsic_reduction_op(intr);
2172*61046927SAndroid Build Coastguard Worker nir_def *subgroup_id = nir_load_subgroup_invocation(b);
2173*61046927SAndroid Build Coastguard Worker nir_def *subgroup_size = nir_load_subgroup_size(b);
2174*61046927SAndroid Build Coastguard Worker nir_def *active_threads = nir_ballot(b, 4, 32, nir_imm_true(b));
2175*61046927SAndroid Build Coastguard Worker nir_def *base_value;
2176*61046927SAndroid Build Coastguard Worker uint32_t bit_size = intr->def.bit_size;
2177*61046927SAndroid Build Coastguard Worker if (op == nir_op_iand || op == nir_op_umin)
2178*61046927SAndroid Build Coastguard Worker base_value = nir_imm_intN_t(b, ~0ull, bit_size);
2179*61046927SAndroid Build Coastguard Worker else if (op == nir_op_imin)
2180*61046927SAndroid Build Coastguard Worker base_value = nir_imm_intN_t(b, (1ull << (bit_size - 1)) - 1, bit_size);
2181*61046927SAndroid Build Coastguard Worker else if (op == nir_op_imax)
2182*61046927SAndroid Build Coastguard Worker base_value = nir_imm_intN_t(b, 1ull << (bit_size - 1), bit_size);
2183*61046927SAndroid Build Coastguard Worker else if (op == nir_op_fmax)
2184*61046927SAndroid Build Coastguard Worker base_value = nir_imm_floatN_t(b, -INFINITY, bit_size);
2185*61046927SAndroid Build Coastguard Worker else if (op == nir_op_fmin)
2186*61046927SAndroid Build Coastguard Worker base_value = nir_imm_floatN_t(b, INFINITY, bit_size);
2187*61046927SAndroid Build Coastguard Worker else
2188*61046927SAndroid Build Coastguard Worker base_value = nir_imm_intN_t(b, 0, bit_size);
2189*61046927SAndroid Build Coastguard Worker
2190*61046927SAndroid Build Coastguard Worker nir_variable *loop_counter_var = nir_local_variable_create(b->impl, glsl_uint_type(), "subgroup_loop_counter");
2191*61046927SAndroid Build Coastguard Worker nir_variable *result_var = nir_local_variable_create(b->impl,
2192*61046927SAndroid Build Coastguard Worker glsl_vector_type(nir_get_glsl_base_type_for_nir_type(
2193*61046927SAndroid Build Coastguard Worker nir_op_infos[op].input_types[0] | bit_size), 1),
2194*61046927SAndroid Build Coastguard Worker "subgroup_loop_result");
2195*61046927SAndroid Build Coastguard Worker nir_store_var(b, loop_counter_var, nir_imm_int(b, 0), 1);
2196*61046927SAndroid Build Coastguard Worker nir_store_var(b, result_var, base_value, 1);
2197*61046927SAndroid Build Coastguard Worker nir_loop *loop = nir_push_loop(b);
2198*61046927SAndroid Build Coastguard Worker nir_def *loop_counter = nir_load_var(b, loop_counter_var);
2199*61046927SAndroid Build Coastguard Worker
2200*61046927SAndroid Build Coastguard Worker nir_if *nif = nir_push_if(b, nir_ilt(b, loop_counter, subgroup_size));
2201*61046927SAndroid Build Coastguard Worker nir_def *other_thread_val = nir_read_invocation(b, intr->src[0].ssa, loop_counter);
2202*61046927SAndroid Build Coastguard Worker nir_def *thread_in_range = intr->intrinsic == nir_intrinsic_inclusive_scan ?
2203*61046927SAndroid Build Coastguard Worker nir_ige(b, subgroup_id, loop_counter) :
2204*61046927SAndroid Build Coastguard Worker nir_ilt(b, loop_counter, subgroup_id);
2205*61046927SAndroid Build Coastguard Worker nir_def *thread_active = nir_ballot_bitfield_extract(b, 1, active_threads, loop_counter);
2206*61046927SAndroid Build Coastguard Worker
2207*61046927SAndroid Build Coastguard Worker nir_if *if_active_thread = nir_push_if(b, nir_iand(b, thread_in_range, thread_active));
2208*61046927SAndroid Build Coastguard Worker nir_def *result = nir_build_alu2(b, op, nir_load_var(b, result_var), other_thread_val);
2209*61046927SAndroid Build Coastguard Worker nir_store_var(b, result_var, result, 1);
2210*61046927SAndroid Build Coastguard Worker nir_pop_if(b, if_active_thread);
2211*61046927SAndroid Build Coastguard Worker
2212*61046927SAndroid Build Coastguard Worker nir_store_var(b, loop_counter_var, nir_iadd_imm(b, loop_counter, 1), 1);
2213*61046927SAndroid Build Coastguard Worker nir_jump(b, nir_jump_continue);
2214*61046927SAndroid Build Coastguard Worker nir_pop_if(b, nif);
2215*61046927SAndroid Build Coastguard Worker
2216*61046927SAndroid Build Coastguard Worker nir_jump(b, nir_jump_break);
2217*61046927SAndroid Build Coastguard Worker nir_pop_loop(b, loop);
2218*61046927SAndroid Build Coastguard Worker
2219*61046927SAndroid Build Coastguard Worker result = nir_load_var(b, result_var);
2220*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&intr->def, result);
2221*61046927SAndroid Build Coastguard Worker return true;
2222*61046927SAndroid Build Coastguard Worker }
2223*61046927SAndroid Build Coastguard Worker
2224*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_unsupported_subgroup_scan(nir_shader * s)2225*61046927SAndroid Build Coastguard Worker dxil_nir_lower_unsupported_subgroup_scan(nir_shader *s)
2226*61046927SAndroid Build Coastguard Worker {
2227*61046927SAndroid Build Coastguard Worker bool ret = nir_shader_intrinsics_pass(s, lower_subgroup_scan,
2228*61046927SAndroid Build Coastguard Worker nir_metadata_none, NULL);
2229*61046927SAndroid Build Coastguard Worker if (ret) {
2230*61046927SAndroid Build Coastguard Worker /* Lower the ballot bitfield tests */
2231*61046927SAndroid Build Coastguard Worker nir_lower_subgroups_options options = { .ballot_bit_size = 32, .ballot_components = 4 };
2232*61046927SAndroid Build Coastguard Worker nir_lower_subgroups(s, &options);
2233*61046927SAndroid Build Coastguard Worker }
2234*61046927SAndroid Build Coastguard Worker return ret;
2235*61046927SAndroid Build Coastguard Worker }
2236*61046927SAndroid Build Coastguard Worker
2237*61046927SAndroid Build Coastguard Worker bool
dxil_nir_forward_front_face(nir_shader * nir)2238*61046927SAndroid Build Coastguard Worker dxil_nir_forward_front_face(nir_shader *nir)
2239*61046927SAndroid Build Coastguard Worker {
2240*61046927SAndroid Build Coastguard Worker assert(nir->info.stage == MESA_SHADER_FRAGMENT);
2241*61046927SAndroid Build Coastguard Worker
2242*61046927SAndroid Build Coastguard Worker nir_variable *var = nir_find_variable_with_location(nir, nir_var_shader_in, VARYING_SLOT_FACE);
2243*61046927SAndroid Build Coastguard Worker if (var) {
2244*61046927SAndroid Build Coastguard Worker var->data.location = VARYING_SLOT_VAR12;
2245*61046927SAndroid Build Coastguard Worker return true;
2246*61046927SAndroid Build Coastguard Worker }
2247*61046927SAndroid Build Coastguard Worker return false;
2248*61046927SAndroid Build Coastguard Worker }
2249*61046927SAndroid Build Coastguard Worker
2250*61046927SAndroid Build Coastguard Worker static bool
move_consts(nir_builder * b,nir_instr * instr,void * data)2251*61046927SAndroid Build Coastguard Worker move_consts(nir_builder *b, nir_instr *instr, void *data)
2252*61046927SAndroid Build Coastguard Worker {
2253*61046927SAndroid Build Coastguard Worker bool progress = false;
2254*61046927SAndroid Build Coastguard Worker switch (instr->type) {
2255*61046927SAndroid Build Coastguard Worker case nir_instr_type_load_const: {
2256*61046927SAndroid Build Coastguard Worker /* Sink load_const to their uses if there's multiple */
2257*61046927SAndroid Build Coastguard Worker nir_load_const_instr *load_const = nir_instr_as_load_const(instr);
2258*61046927SAndroid Build Coastguard Worker if (!list_is_singular(&load_const->def.uses)) {
2259*61046927SAndroid Build Coastguard Worker nir_foreach_use_safe(src, &load_const->def) {
2260*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_src(src);
2261*61046927SAndroid Build Coastguard Worker nir_load_const_instr *new_load = nir_load_const_instr_create(b->shader,
2262*61046927SAndroid Build Coastguard Worker load_const->def.num_components,
2263*61046927SAndroid Build Coastguard Worker load_const->def.bit_size);
2264*61046927SAndroid Build Coastguard Worker memcpy(new_load->value, load_const->value, sizeof(load_const->value[0]) * load_const->def.num_components);
2265*61046927SAndroid Build Coastguard Worker nir_builder_instr_insert(b, &new_load->instr);
2266*61046927SAndroid Build Coastguard Worker nir_src_rewrite(src, &new_load->def);
2267*61046927SAndroid Build Coastguard Worker progress = true;
2268*61046927SAndroid Build Coastguard Worker }
2269*61046927SAndroid Build Coastguard Worker }
2270*61046927SAndroid Build Coastguard Worker return progress;
2271*61046927SAndroid Build Coastguard Worker }
2272*61046927SAndroid Build Coastguard Worker default:
2273*61046927SAndroid Build Coastguard Worker return false;
2274*61046927SAndroid Build Coastguard Worker }
2275*61046927SAndroid Build Coastguard Worker }
2276*61046927SAndroid Build Coastguard Worker
2277*61046927SAndroid Build Coastguard Worker /* Sink all consts so that they have only have a single use.
2278*61046927SAndroid Build Coastguard Worker * The DXIL backend will already de-dupe the constants to the
2279*61046927SAndroid Build Coastguard Worker * same dxil_value if they have the same type, but this allows a single constant
2280*61046927SAndroid Build Coastguard Worker * to have different types without bitcasts. */
2281*61046927SAndroid Build Coastguard Worker bool
dxil_nir_move_consts(nir_shader * s)2282*61046927SAndroid Build Coastguard Worker dxil_nir_move_consts(nir_shader *s)
2283*61046927SAndroid Build Coastguard Worker {
2284*61046927SAndroid Build Coastguard Worker return nir_shader_instructions_pass(s, move_consts,
2285*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow,
2286*61046927SAndroid Build Coastguard Worker NULL);
2287*61046927SAndroid Build Coastguard Worker }
2288*61046927SAndroid Build Coastguard Worker
2289*61046927SAndroid Build Coastguard Worker static void
clear_pass_flags(nir_function_impl * impl)2290*61046927SAndroid Build Coastguard Worker clear_pass_flags(nir_function_impl *impl)
2291*61046927SAndroid Build Coastguard Worker {
2292*61046927SAndroid Build Coastguard Worker nir_foreach_block(block, impl) {
2293*61046927SAndroid Build Coastguard Worker nir_foreach_instr(instr, block) {
2294*61046927SAndroid Build Coastguard Worker instr->pass_flags = 0;
2295*61046927SAndroid Build Coastguard Worker }
2296*61046927SAndroid Build Coastguard Worker }
2297*61046927SAndroid Build Coastguard Worker }
2298*61046927SAndroid Build Coastguard Worker
2299*61046927SAndroid Build Coastguard Worker static bool
add_def_to_worklist(nir_def * def,void * state)2300*61046927SAndroid Build Coastguard Worker add_def_to_worklist(nir_def *def, void *state)
2301*61046927SAndroid Build Coastguard Worker {
2302*61046927SAndroid Build Coastguard Worker nir_foreach_use_including_if(src, def) {
2303*61046927SAndroid Build Coastguard Worker if (nir_src_is_if(src)) {
2304*61046927SAndroid Build Coastguard Worker nir_if *nif = nir_src_parent_if(src);
2305*61046927SAndroid Build Coastguard Worker nir_foreach_block_in_cf_node(block, &nif->cf_node) {
2306*61046927SAndroid Build Coastguard Worker nir_foreach_instr(instr, block)
2307*61046927SAndroid Build Coastguard Worker nir_instr_worklist_push_tail(state, instr);
2308*61046927SAndroid Build Coastguard Worker }
2309*61046927SAndroid Build Coastguard Worker } else
2310*61046927SAndroid Build Coastguard Worker nir_instr_worklist_push_tail(state, nir_src_parent_instr(src));
2311*61046927SAndroid Build Coastguard Worker }
2312*61046927SAndroid Build Coastguard Worker return true;
2313*61046927SAndroid Build Coastguard Worker }
2314*61046927SAndroid Build Coastguard Worker
2315*61046927SAndroid Build Coastguard Worker static bool
set_input_bits(struct dxil_module * mod,nir_intrinsic_instr * intr,BITSET_WORD * input_bits,uint32_t *** tables,const uint32_t ** table_sizes)2316*61046927SAndroid Build Coastguard Worker set_input_bits(struct dxil_module *mod, nir_intrinsic_instr *intr, BITSET_WORD *input_bits, uint32_t ***tables, const uint32_t **table_sizes)
2317*61046927SAndroid Build Coastguard Worker {
2318*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_load_view_index) {
2319*61046927SAndroid Build Coastguard Worker BITSET_SET(input_bits, 0);
2320*61046927SAndroid Build Coastguard Worker return true;
2321*61046927SAndroid Build Coastguard Worker }
2322*61046927SAndroid Build Coastguard Worker
2323*61046927SAndroid Build Coastguard Worker bool any_bits_set = false;
2324*61046927SAndroid Build Coastguard Worker nir_src *row_src = intr->intrinsic == nir_intrinsic_load_per_vertex_input ? &intr->src[1] : &intr->src[0];
2325*61046927SAndroid Build Coastguard Worker bool is_patch_constant = mod->shader_kind == DXIL_DOMAIN_SHADER && intr->intrinsic == nir_intrinsic_load_input;
2326*61046927SAndroid Build Coastguard Worker const struct dxil_signature_record *sig_rec = is_patch_constant ?
2327*61046927SAndroid Build Coastguard Worker &mod->patch_consts[nir_intrinsic_base(intr)] :
2328*61046927SAndroid Build Coastguard Worker &mod->inputs[mod->input_mappings[nir_intrinsic_base(intr)]];
2329*61046927SAndroid Build Coastguard Worker if (is_patch_constant) {
2330*61046927SAndroid Build Coastguard Worker /* Redirect to the second I/O table */
2331*61046927SAndroid Build Coastguard Worker *tables = *tables + 1;
2332*61046927SAndroid Build Coastguard Worker *table_sizes = *table_sizes + 1;
2333*61046927SAndroid Build Coastguard Worker }
2334*61046927SAndroid Build Coastguard Worker for (uint32_t component = 0; component < intr->num_components; ++component) {
2335*61046927SAndroid Build Coastguard Worker uint32_t base_element = 0;
2336*61046927SAndroid Build Coastguard Worker uint32_t num_elements = sig_rec->num_elements;
2337*61046927SAndroid Build Coastguard Worker if (nir_src_is_const(*row_src)) {
2338*61046927SAndroid Build Coastguard Worker base_element = (uint32_t)nir_src_as_uint(*row_src);
2339*61046927SAndroid Build Coastguard Worker num_elements = 1;
2340*61046927SAndroid Build Coastguard Worker }
2341*61046927SAndroid Build Coastguard Worker for (uint32_t element = 0; element < num_elements; ++element) {
2342*61046927SAndroid Build Coastguard Worker uint32_t row = sig_rec->elements[element + base_element].reg;
2343*61046927SAndroid Build Coastguard Worker if (row == 0xffffffff)
2344*61046927SAndroid Build Coastguard Worker continue;
2345*61046927SAndroid Build Coastguard Worker BITSET_SET(input_bits, row * 4 + component + nir_intrinsic_component(intr));
2346*61046927SAndroid Build Coastguard Worker any_bits_set = true;
2347*61046927SAndroid Build Coastguard Worker }
2348*61046927SAndroid Build Coastguard Worker }
2349*61046927SAndroid Build Coastguard Worker return any_bits_set;
2350*61046927SAndroid Build Coastguard Worker }
2351*61046927SAndroid Build Coastguard Worker
2352*61046927SAndroid Build Coastguard Worker static bool
set_output_bits(struct dxil_module * mod,nir_intrinsic_instr * intr,BITSET_WORD * input_bits,uint32_t ** tables,const uint32_t * table_sizes)2353*61046927SAndroid Build Coastguard Worker set_output_bits(struct dxil_module *mod, nir_intrinsic_instr *intr, BITSET_WORD *input_bits, uint32_t **tables, const uint32_t *table_sizes)
2354*61046927SAndroid Build Coastguard Worker {
2355*61046927SAndroid Build Coastguard Worker bool any_bits_set = false;
2356*61046927SAndroid Build Coastguard Worker nir_src *row_src = intr->intrinsic == nir_intrinsic_store_per_vertex_output ? &intr->src[2] : &intr->src[1];
2357*61046927SAndroid Build Coastguard Worker bool is_patch_constant = mod->shader_kind == DXIL_HULL_SHADER && intr->intrinsic == nir_intrinsic_store_output;
2358*61046927SAndroid Build Coastguard Worker const struct dxil_signature_record *sig_rec = is_patch_constant ?
2359*61046927SAndroid Build Coastguard Worker &mod->patch_consts[nir_intrinsic_base(intr)] :
2360*61046927SAndroid Build Coastguard Worker &mod->outputs[nir_intrinsic_base(intr)];
2361*61046927SAndroid Build Coastguard Worker for (uint32_t component = 0; component < intr->num_components; ++component) {
2362*61046927SAndroid Build Coastguard Worker uint32_t base_element = 0;
2363*61046927SAndroid Build Coastguard Worker uint32_t num_elements = sig_rec->num_elements;
2364*61046927SAndroid Build Coastguard Worker if (nir_src_is_const(*row_src)) {
2365*61046927SAndroid Build Coastguard Worker base_element = (uint32_t)nir_src_as_uint(*row_src);
2366*61046927SAndroid Build Coastguard Worker num_elements = 1;
2367*61046927SAndroid Build Coastguard Worker }
2368*61046927SAndroid Build Coastguard Worker for (uint32_t element = 0; element < num_elements; ++element) {
2369*61046927SAndroid Build Coastguard Worker uint32_t row = sig_rec->elements[element + base_element].reg;
2370*61046927SAndroid Build Coastguard Worker if (row == 0xffffffff)
2371*61046927SAndroid Build Coastguard Worker continue;
2372*61046927SAndroid Build Coastguard Worker uint32_t stream = sig_rec->elements[element + base_element].stream;
2373*61046927SAndroid Build Coastguard Worker uint32_t table_idx = is_patch_constant ? 1 : stream;
2374*61046927SAndroid Build Coastguard Worker uint32_t *table = tables[table_idx];
2375*61046927SAndroid Build Coastguard Worker uint32_t output_component = component + nir_intrinsic_component(intr);
2376*61046927SAndroid Build Coastguard Worker uint32_t input_component;
2377*61046927SAndroid Build Coastguard Worker BITSET_FOREACH_SET(input_component, input_bits, 32 * 4) {
2378*61046927SAndroid Build Coastguard Worker uint32_t *table_for_input_component = table + table_sizes[table_idx] * input_component;
2379*61046927SAndroid Build Coastguard Worker BITSET_SET(table_for_input_component, row * 4 + output_component);
2380*61046927SAndroid Build Coastguard Worker any_bits_set = true;
2381*61046927SAndroid Build Coastguard Worker }
2382*61046927SAndroid Build Coastguard Worker }
2383*61046927SAndroid Build Coastguard Worker }
2384*61046927SAndroid Build Coastguard Worker return any_bits_set;
2385*61046927SAndroid Build Coastguard Worker }
2386*61046927SAndroid Build Coastguard Worker
2387*61046927SAndroid Build Coastguard Worker static bool
propagate_input_to_output_dependencies(struct dxil_module * mod,nir_intrinsic_instr * load_intr,uint32_t ** tables,const uint32_t * table_sizes)2388*61046927SAndroid Build Coastguard Worker propagate_input_to_output_dependencies(struct dxil_module *mod, nir_intrinsic_instr *load_intr, uint32_t **tables, const uint32_t *table_sizes)
2389*61046927SAndroid Build Coastguard Worker {
2390*61046927SAndroid Build Coastguard Worker /* Which input components are being loaded by this instruction */
2391*61046927SAndroid Build Coastguard Worker BITSET_DECLARE(input_bits, 32 * 4) = { 0 };
2392*61046927SAndroid Build Coastguard Worker if (!set_input_bits(mod, load_intr, input_bits, &tables, &table_sizes))
2393*61046927SAndroid Build Coastguard Worker return false;
2394*61046927SAndroid Build Coastguard Worker
2395*61046927SAndroid Build Coastguard Worker nir_instr_worklist *worklist = nir_instr_worklist_create();
2396*61046927SAndroid Build Coastguard Worker nir_instr_worklist_push_tail(worklist, &load_intr->instr);
2397*61046927SAndroid Build Coastguard Worker bool any_bits_set = false;
2398*61046927SAndroid Build Coastguard Worker nir_foreach_instr_in_worklist(instr, worklist) {
2399*61046927SAndroid Build Coastguard Worker if (instr->pass_flags)
2400*61046927SAndroid Build Coastguard Worker continue;
2401*61046927SAndroid Build Coastguard Worker
2402*61046927SAndroid Build Coastguard Worker instr->pass_flags = 1;
2403*61046927SAndroid Build Coastguard Worker nir_foreach_def(instr, add_def_to_worklist, worklist);
2404*61046927SAndroid Build Coastguard Worker switch (instr->type) {
2405*61046927SAndroid Build Coastguard Worker case nir_instr_type_jump: {
2406*61046927SAndroid Build Coastguard Worker nir_jump_instr *jump = nir_instr_as_jump(instr);
2407*61046927SAndroid Build Coastguard Worker switch (jump->type) {
2408*61046927SAndroid Build Coastguard Worker case nir_jump_break:
2409*61046927SAndroid Build Coastguard Worker case nir_jump_continue: {
2410*61046927SAndroid Build Coastguard Worker nir_cf_node *parent = &instr->block->cf_node;
2411*61046927SAndroid Build Coastguard Worker while (parent->type != nir_cf_node_loop)
2412*61046927SAndroid Build Coastguard Worker parent = parent->parent;
2413*61046927SAndroid Build Coastguard Worker nir_foreach_block_in_cf_node(block, parent)
2414*61046927SAndroid Build Coastguard Worker nir_foreach_instr(i, block)
2415*61046927SAndroid Build Coastguard Worker nir_instr_worklist_push_tail(worklist, i);
2416*61046927SAndroid Build Coastguard Worker }
2417*61046927SAndroid Build Coastguard Worker break;
2418*61046927SAndroid Build Coastguard Worker default:
2419*61046927SAndroid Build Coastguard Worker unreachable("Don't expect any other jumps");
2420*61046927SAndroid Build Coastguard Worker }
2421*61046927SAndroid Build Coastguard Worker break;
2422*61046927SAndroid Build Coastguard Worker }
2423*61046927SAndroid Build Coastguard Worker case nir_instr_type_intrinsic: {
2424*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
2425*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
2426*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_output:
2427*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_per_vertex_output:
2428*61046927SAndroid Build Coastguard Worker any_bits_set |= set_output_bits(mod, intr, input_bits, tables, table_sizes);
2429*61046927SAndroid Build Coastguard Worker break;
2430*61046927SAndroid Build Coastguard Worker /* TODO: Memory writes */
2431*61046927SAndroid Build Coastguard Worker default:
2432*61046927SAndroid Build Coastguard Worker break;
2433*61046927SAndroid Build Coastguard Worker }
2434*61046927SAndroid Build Coastguard Worker break;
2435*61046927SAndroid Build Coastguard Worker }
2436*61046927SAndroid Build Coastguard Worker default:
2437*61046927SAndroid Build Coastguard Worker break;
2438*61046927SAndroid Build Coastguard Worker }
2439*61046927SAndroid Build Coastguard Worker }
2440*61046927SAndroid Build Coastguard Worker
2441*61046927SAndroid Build Coastguard Worker nir_instr_worklist_destroy(worklist);
2442*61046927SAndroid Build Coastguard Worker return any_bits_set;
2443*61046927SAndroid Build Coastguard Worker }
2444*61046927SAndroid Build Coastguard Worker
2445*61046927SAndroid Build Coastguard Worker /* For every input load, compute the set of output stores that it can contribute to.
2446*61046927SAndroid Build Coastguard Worker * If it contributes to a store to memory, If it's used for control flow, then any
2447*61046927SAndroid Build Coastguard Worker * instruction in the CFG that it impacts is considered to contribute.
2448*61046927SAndroid Build Coastguard Worker * Ideally, we should also handle stores to outputs/memory and then loads from that
2449*61046927SAndroid Build Coastguard Worker * output/memory, but this is non-trivial and unclear how much impact that would have. */
2450*61046927SAndroid Build Coastguard Worker bool
dxil_nir_analyze_io_dependencies(struct dxil_module * mod,nir_shader * s)2451*61046927SAndroid Build Coastguard Worker dxil_nir_analyze_io_dependencies(struct dxil_module *mod, nir_shader *s)
2452*61046927SAndroid Build Coastguard Worker {
2453*61046927SAndroid Build Coastguard Worker bool any_outputs = false;
2454*61046927SAndroid Build Coastguard Worker for (uint32_t i = 0; i < 4; ++i)
2455*61046927SAndroid Build Coastguard Worker any_outputs |= mod->num_psv_outputs[i] > 0;
2456*61046927SAndroid Build Coastguard Worker if (mod->shader_kind == DXIL_HULL_SHADER)
2457*61046927SAndroid Build Coastguard Worker any_outputs |= mod->num_psv_patch_consts > 0;
2458*61046927SAndroid Build Coastguard Worker if (!any_outputs)
2459*61046927SAndroid Build Coastguard Worker return false;
2460*61046927SAndroid Build Coastguard Worker
2461*61046927SAndroid Build Coastguard Worker bool any_bits_set = false;
2462*61046927SAndroid Build Coastguard Worker nir_foreach_function(func, s) {
2463*61046927SAndroid Build Coastguard Worker assert(func->impl);
2464*61046927SAndroid Build Coastguard Worker /* Hull shaders have a patch constant function */
2465*61046927SAndroid Build Coastguard Worker assert(func->is_entrypoint || s->info.stage == MESA_SHADER_TESS_CTRL);
2466*61046927SAndroid Build Coastguard Worker
2467*61046927SAndroid Build Coastguard Worker /* Pass 1: input/view ID -> output dependencies */
2468*61046927SAndroid Build Coastguard Worker nir_foreach_block(block, func->impl) {
2469*61046927SAndroid Build Coastguard Worker nir_foreach_instr(instr, block) {
2470*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_intrinsic)
2471*61046927SAndroid Build Coastguard Worker continue;
2472*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
2473*61046927SAndroid Build Coastguard Worker uint32_t **tables = mod->io_dependency_table;
2474*61046927SAndroid Build Coastguard Worker const uint32_t *table_sizes = mod->dependency_table_dwords_per_input;
2475*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
2476*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_view_index:
2477*61046927SAndroid Build Coastguard Worker tables = mod->viewid_dependency_table;
2478*61046927SAndroid Build Coastguard Worker FALLTHROUGH;
2479*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_input:
2480*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_per_vertex_input:
2481*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_interpolated_input:
2482*61046927SAndroid Build Coastguard Worker break;
2483*61046927SAndroid Build Coastguard Worker default:
2484*61046927SAndroid Build Coastguard Worker continue;
2485*61046927SAndroid Build Coastguard Worker }
2486*61046927SAndroid Build Coastguard Worker
2487*61046927SAndroid Build Coastguard Worker clear_pass_flags(func->impl);
2488*61046927SAndroid Build Coastguard Worker any_bits_set |= propagate_input_to_output_dependencies(mod, intr, tables, table_sizes);
2489*61046927SAndroid Build Coastguard Worker }
2490*61046927SAndroid Build Coastguard Worker }
2491*61046927SAndroid Build Coastguard Worker
2492*61046927SAndroid Build Coastguard Worker /* Pass 2: output -> output dependencies */
2493*61046927SAndroid Build Coastguard Worker /* TODO */
2494*61046927SAndroid Build Coastguard Worker }
2495*61046927SAndroid Build Coastguard Worker return any_bits_set;
2496*61046927SAndroid Build Coastguard Worker }
2497*61046927SAndroid Build Coastguard Worker
2498*61046927SAndroid Build Coastguard Worker static enum pipe_format
get_format_for_var(unsigned num_comps,enum glsl_base_type sampled_type)2499*61046927SAndroid Build Coastguard Worker get_format_for_var(unsigned num_comps, enum glsl_base_type sampled_type)
2500*61046927SAndroid Build Coastguard Worker {
2501*61046927SAndroid Build Coastguard Worker switch (sampled_type) {
2502*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_INT:
2503*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_INT64:
2504*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_INT16:
2505*61046927SAndroid Build Coastguard Worker switch (num_comps) {
2506*61046927SAndroid Build Coastguard Worker case 1: return PIPE_FORMAT_R32_SINT;
2507*61046927SAndroid Build Coastguard Worker case 2: return PIPE_FORMAT_R32G32_SINT;
2508*61046927SAndroid Build Coastguard Worker case 3: return PIPE_FORMAT_R32G32B32_SINT;
2509*61046927SAndroid Build Coastguard Worker case 4: return PIPE_FORMAT_R32G32B32A32_SINT;
2510*61046927SAndroid Build Coastguard Worker default: unreachable("Invalid num_comps");
2511*61046927SAndroid Build Coastguard Worker }
2512*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_UINT:
2513*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_UINT64:
2514*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_UINT16:
2515*61046927SAndroid Build Coastguard Worker switch (num_comps) {
2516*61046927SAndroid Build Coastguard Worker case 1: return PIPE_FORMAT_R32_UINT;
2517*61046927SAndroid Build Coastguard Worker case 2: return PIPE_FORMAT_R32G32_UINT;
2518*61046927SAndroid Build Coastguard Worker case 3: return PIPE_FORMAT_R32G32B32_UINT;
2519*61046927SAndroid Build Coastguard Worker case 4: return PIPE_FORMAT_R32G32B32A32_UINT;
2520*61046927SAndroid Build Coastguard Worker default: unreachable("Invalid num_comps");
2521*61046927SAndroid Build Coastguard Worker }
2522*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_FLOAT:
2523*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_FLOAT16:
2524*61046927SAndroid Build Coastguard Worker case GLSL_TYPE_DOUBLE:
2525*61046927SAndroid Build Coastguard Worker switch (num_comps) {
2526*61046927SAndroid Build Coastguard Worker case 1: return PIPE_FORMAT_R32_FLOAT;
2527*61046927SAndroid Build Coastguard Worker case 2: return PIPE_FORMAT_R32G32_FLOAT;
2528*61046927SAndroid Build Coastguard Worker case 3: return PIPE_FORMAT_R32G32B32_FLOAT;
2529*61046927SAndroid Build Coastguard Worker case 4: return PIPE_FORMAT_R32G32B32A32_FLOAT;
2530*61046927SAndroid Build Coastguard Worker default: unreachable("Invalid num_comps");
2531*61046927SAndroid Build Coastguard Worker }
2532*61046927SAndroid Build Coastguard Worker default: unreachable("Invalid sampler return type");
2533*61046927SAndroid Build Coastguard Worker }
2534*61046927SAndroid Build Coastguard Worker }
2535*61046927SAndroid Build Coastguard Worker
2536*61046927SAndroid Build Coastguard Worker static unsigned
aoa_size(const struct glsl_type * type)2537*61046927SAndroid Build Coastguard Worker aoa_size(const struct glsl_type *type)
2538*61046927SAndroid Build Coastguard Worker {
2539*61046927SAndroid Build Coastguard Worker return glsl_type_is_array(type) ? glsl_get_aoa_size(type) : 1;
2540*61046927SAndroid Build Coastguard Worker }
2541*61046927SAndroid Build Coastguard Worker
2542*61046927SAndroid Build Coastguard Worker static bool
guess_image_format_for_var(nir_shader * s,nir_variable * var)2543*61046927SAndroid Build Coastguard Worker guess_image_format_for_var(nir_shader *s, nir_variable *var)
2544*61046927SAndroid Build Coastguard Worker {
2545*61046927SAndroid Build Coastguard Worker const struct glsl_type *base_type = glsl_without_array(var->type);
2546*61046927SAndroid Build Coastguard Worker if (!glsl_type_is_image(base_type))
2547*61046927SAndroid Build Coastguard Worker return false;
2548*61046927SAndroid Build Coastguard Worker if (var->data.image.format != PIPE_FORMAT_NONE)
2549*61046927SAndroid Build Coastguard Worker return false;
2550*61046927SAndroid Build Coastguard Worker
2551*61046927SAndroid Build Coastguard Worker nir_foreach_function_impl(impl, s) {
2552*61046927SAndroid Build Coastguard Worker nir_foreach_block(block, impl) {
2553*61046927SAndroid Build Coastguard Worker nir_foreach_instr(instr, block) {
2554*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_intrinsic)
2555*61046927SAndroid Build Coastguard Worker continue;
2556*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
2557*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
2558*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_deref_load:
2559*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_deref_store:
2560*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_deref_atomic:
2561*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_deref_atomic_swap:
2562*61046927SAndroid Build Coastguard Worker if (nir_intrinsic_get_var(intr, 0) != var)
2563*61046927SAndroid Build Coastguard Worker continue;
2564*61046927SAndroid Build Coastguard Worker break;
2565*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_load:
2566*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_store:
2567*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_atomic:
2568*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_atomic_swap: {
2569*61046927SAndroid Build Coastguard Worker unsigned binding = nir_src_as_uint(intr->src[0]);
2570*61046927SAndroid Build Coastguard Worker if (binding < var->data.binding ||
2571*61046927SAndroid Build Coastguard Worker binding >= var->data.binding + aoa_size(var->type))
2572*61046927SAndroid Build Coastguard Worker continue;
2573*61046927SAndroid Build Coastguard Worker break;
2574*61046927SAndroid Build Coastguard Worker }
2575*61046927SAndroid Build Coastguard Worker default:
2576*61046927SAndroid Build Coastguard Worker continue;
2577*61046927SAndroid Build Coastguard Worker }
2578*61046927SAndroid Build Coastguard Worker break;
2579*61046927SAndroid Build Coastguard Worker
2580*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
2581*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_deref_load:
2582*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_load:
2583*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_deref_store:
2584*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_store:
2585*61046927SAndroid Build Coastguard Worker /* Increase unknown formats up to 4 components if a 4-component accessor is used */
2586*61046927SAndroid Build Coastguard Worker if (intr->num_components > util_format_get_nr_components(var->data.image.format))
2587*61046927SAndroid Build Coastguard Worker var->data.image.format = get_format_for_var(intr->num_components, glsl_get_sampler_result_type(base_type));
2588*61046927SAndroid Build Coastguard Worker break;
2589*61046927SAndroid Build Coastguard Worker default:
2590*61046927SAndroid Build Coastguard Worker /* If an atomic is used, the image format must be 1-component; return immediately */
2591*61046927SAndroid Build Coastguard Worker var->data.image.format = get_format_for_var(1, glsl_get_sampler_result_type(base_type));
2592*61046927SAndroid Build Coastguard Worker return true;
2593*61046927SAndroid Build Coastguard Worker }
2594*61046927SAndroid Build Coastguard Worker }
2595*61046927SAndroid Build Coastguard Worker }
2596*61046927SAndroid Build Coastguard Worker }
2597*61046927SAndroid Build Coastguard Worker /* Dunno what it is, assume 4-component */
2598*61046927SAndroid Build Coastguard Worker if (var->data.image.format == PIPE_FORMAT_NONE)
2599*61046927SAndroid Build Coastguard Worker var->data.image.format = get_format_for_var(4, glsl_get_sampler_result_type(base_type));
2600*61046927SAndroid Build Coastguard Worker return true;
2601*61046927SAndroid Build Coastguard Worker }
2602*61046927SAndroid Build Coastguard Worker
2603*61046927SAndroid Build Coastguard Worker static void
update_intrinsic_format_and_type(nir_intrinsic_instr * intr,nir_variable * var)2604*61046927SAndroid Build Coastguard Worker update_intrinsic_format_and_type(nir_intrinsic_instr *intr, nir_variable *var)
2605*61046927SAndroid Build Coastguard Worker {
2606*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_format(intr, var->data.image.format);
2607*61046927SAndroid Build Coastguard Worker nir_alu_type alu_type =
2608*61046927SAndroid Build Coastguard Worker nir_get_nir_type_for_glsl_base_type(glsl_get_sampler_result_type(glsl_without_array(var->type)));
2609*61046927SAndroid Build Coastguard Worker if (nir_intrinsic_has_src_type(intr))
2610*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_src_type(intr, alu_type);
2611*61046927SAndroid Build Coastguard Worker else if (nir_intrinsic_has_dest_type(intr))
2612*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_dest_type(intr, alu_type);
2613*61046927SAndroid Build Coastguard Worker }
2614*61046927SAndroid Build Coastguard Worker
2615*61046927SAndroid Build Coastguard Worker static bool
update_intrinsic_formats(nir_builder * b,nir_intrinsic_instr * intr,void * data)2616*61046927SAndroid Build Coastguard Worker update_intrinsic_formats(nir_builder *b, nir_intrinsic_instr *intr,
2617*61046927SAndroid Build Coastguard Worker void *data)
2618*61046927SAndroid Build Coastguard Worker {
2619*61046927SAndroid Build Coastguard Worker if (!nir_intrinsic_has_format(intr))
2620*61046927SAndroid Build Coastguard Worker return false;
2621*61046927SAndroid Build Coastguard Worker nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
2622*61046927SAndroid Build Coastguard Worker if (deref) {
2623*61046927SAndroid Build Coastguard Worker nir_variable *var = nir_deref_instr_get_variable(deref);
2624*61046927SAndroid Build Coastguard Worker if (var)
2625*61046927SAndroid Build Coastguard Worker update_intrinsic_format_and_type(intr, var);
2626*61046927SAndroid Build Coastguard Worker return var != NULL;
2627*61046927SAndroid Build Coastguard Worker }
2628*61046927SAndroid Build Coastguard Worker
2629*61046927SAndroid Build Coastguard Worker if (!nir_intrinsic_has_range_base(intr))
2630*61046927SAndroid Build Coastguard Worker return false;
2631*61046927SAndroid Build Coastguard Worker
2632*61046927SAndroid Build Coastguard Worker unsigned binding = nir_src_as_uint(intr->src[0]);
2633*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, b->shader, nir_var_image) {
2634*61046927SAndroid Build Coastguard Worker if (var->data.binding <= binding &&
2635*61046927SAndroid Build Coastguard Worker var->data.binding + aoa_size(var->type) > binding) {
2636*61046927SAndroid Build Coastguard Worker update_intrinsic_format_and_type(intr, var);
2637*61046927SAndroid Build Coastguard Worker return true;
2638*61046927SAndroid Build Coastguard Worker }
2639*61046927SAndroid Build Coastguard Worker }
2640*61046927SAndroid Build Coastguard Worker return false;
2641*61046927SAndroid Build Coastguard Worker }
2642*61046927SAndroid Build Coastguard Worker
2643*61046927SAndroid Build Coastguard Worker bool
dxil_nir_guess_image_formats(nir_shader * s)2644*61046927SAndroid Build Coastguard Worker dxil_nir_guess_image_formats(nir_shader *s)
2645*61046927SAndroid Build Coastguard Worker {
2646*61046927SAndroid Build Coastguard Worker bool progress = false;
2647*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, s, nir_var_image) {
2648*61046927SAndroid Build Coastguard Worker progress |= guess_image_format_for_var(s, var);
2649*61046927SAndroid Build Coastguard Worker }
2650*61046927SAndroid Build Coastguard Worker nir_shader_intrinsics_pass(s, update_intrinsic_formats, nir_metadata_all,
2651*61046927SAndroid Build Coastguard Worker NULL);
2652*61046927SAndroid Build Coastguard Worker return progress;
2653*61046927SAndroid Build Coastguard Worker }
2654*61046927SAndroid Build Coastguard Worker
2655*61046927SAndroid Build Coastguard Worker static void
set_binding_variables_coherent(nir_shader * s,nir_binding binding,nir_variable_mode modes)2656*61046927SAndroid Build Coastguard Worker set_binding_variables_coherent(nir_shader *s, nir_binding binding, nir_variable_mode modes)
2657*61046927SAndroid Build Coastguard Worker {
2658*61046927SAndroid Build Coastguard Worker nir_foreach_variable_with_modes(var, s, modes) {
2659*61046927SAndroid Build Coastguard Worker if (var->data.binding == binding.binding &&
2660*61046927SAndroid Build Coastguard Worker var->data.descriptor_set == binding.desc_set) {
2661*61046927SAndroid Build Coastguard Worker var->data.access |= ACCESS_COHERENT;
2662*61046927SAndroid Build Coastguard Worker }
2663*61046927SAndroid Build Coastguard Worker }
2664*61046927SAndroid Build Coastguard Worker }
2665*61046927SAndroid Build Coastguard Worker
2666*61046927SAndroid Build Coastguard Worker static void
set_deref_variables_coherent(nir_shader * s,nir_deref_instr * deref)2667*61046927SAndroid Build Coastguard Worker set_deref_variables_coherent(nir_shader *s, nir_deref_instr *deref)
2668*61046927SAndroid Build Coastguard Worker {
2669*61046927SAndroid Build Coastguard Worker while (deref->deref_type != nir_deref_type_var &&
2670*61046927SAndroid Build Coastguard Worker deref->deref_type != nir_deref_type_cast) {
2671*61046927SAndroid Build Coastguard Worker deref = nir_deref_instr_parent(deref);
2672*61046927SAndroid Build Coastguard Worker }
2673*61046927SAndroid Build Coastguard Worker if (deref->deref_type == nir_deref_type_var) {
2674*61046927SAndroid Build Coastguard Worker deref->var->data.access |= ACCESS_COHERENT;
2675*61046927SAndroid Build Coastguard Worker return;
2676*61046927SAndroid Build Coastguard Worker }
2677*61046927SAndroid Build Coastguard Worker
2678*61046927SAndroid Build Coastguard Worker /* For derefs with casts, we only support pre-lowered Vulkan accesses */
2679*61046927SAndroid Build Coastguard Worker assert(deref->deref_type == nir_deref_type_cast);
2680*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *cast_src = nir_instr_as_intrinsic(deref->parent.ssa->parent_instr);
2681*61046927SAndroid Build Coastguard Worker assert(cast_src->intrinsic == nir_intrinsic_load_vulkan_descriptor);
2682*61046927SAndroid Build Coastguard Worker nir_binding binding = nir_chase_binding(cast_src->src[0]);
2683*61046927SAndroid Build Coastguard Worker set_binding_variables_coherent(s, binding, nir_var_mem_ssbo);
2684*61046927SAndroid Build Coastguard Worker }
2685*61046927SAndroid Build Coastguard Worker
2686*61046927SAndroid Build Coastguard Worker static nir_def *
get_atomic_for_load_store(nir_builder * b,nir_intrinsic_instr * intr,unsigned bit_size)2687*61046927SAndroid Build Coastguard Worker get_atomic_for_load_store(nir_builder *b, nir_intrinsic_instr *intr, unsigned bit_size)
2688*61046927SAndroid Build Coastguard Worker {
2689*61046927SAndroid Build Coastguard Worker nir_def *zero = nir_imm_intN_t(b, 0, bit_size);
2690*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
2691*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_deref:
2692*61046927SAndroid Build Coastguard Worker return nir_deref_atomic(b, bit_size, intr->src[0].ssa, zero, .atomic_op = nir_atomic_op_iadd);
2693*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_ssbo:
2694*61046927SAndroid Build Coastguard Worker return nir_ssbo_atomic(b, bit_size, intr->src[0].ssa, intr->src[1].ssa, zero, .atomic_op = nir_atomic_op_iadd);
2695*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_deref_load:
2696*61046927SAndroid Build Coastguard Worker return nir_image_deref_atomic(b, bit_size, intr->src[0].ssa, intr->src[1].ssa, intr->src[2].ssa, zero, .atomic_op = nir_atomic_op_iadd);
2697*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_load:
2698*61046927SAndroid Build Coastguard Worker return nir_image_atomic(b, bit_size, intr->src[0].ssa, intr->src[1].ssa, intr->src[2].ssa, zero, .atomic_op = nir_atomic_op_iadd);
2699*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_deref:
2700*61046927SAndroid Build Coastguard Worker return nir_deref_atomic(b, bit_size, intr->src[0].ssa, intr->src[1].ssa, .atomic_op = nir_atomic_op_xchg);
2701*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_ssbo:
2702*61046927SAndroid Build Coastguard Worker return nir_ssbo_atomic(b, bit_size, intr->src[1].ssa, intr->src[2].ssa, intr->src[0].ssa, .atomic_op = nir_atomic_op_xchg);
2703*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_deref_store:
2704*61046927SAndroid Build Coastguard Worker return nir_image_deref_atomic(b, bit_size, intr->src[0].ssa, intr->src[1].ssa, intr->src[2].ssa, intr->src[3].ssa, .atomic_op = nir_atomic_op_xchg);
2705*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_store:
2706*61046927SAndroid Build Coastguard Worker return nir_image_atomic(b, bit_size, intr->src[0].ssa, intr->src[1].ssa, intr->src[2].ssa, intr->src[3].ssa, .atomic_op = nir_atomic_op_xchg);
2707*61046927SAndroid Build Coastguard Worker default:
2708*61046927SAndroid Build Coastguard Worker return NULL;
2709*61046927SAndroid Build Coastguard Worker }
2710*61046927SAndroid Build Coastguard Worker }
2711*61046927SAndroid Build Coastguard Worker
2712*61046927SAndroid Build Coastguard Worker static bool
lower_coherent_load_store(nir_builder * b,nir_intrinsic_instr * intr,void * context)2713*61046927SAndroid Build Coastguard Worker lower_coherent_load_store(nir_builder *b, nir_intrinsic_instr *intr, void *context)
2714*61046927SAndroid Build Coastguard Worker {
2715*61046927SAndroid Build Coastguard Worker if (!nir_intrinsic_has_access(intr) || (nir_intrinsic_access(intr) & ACCESS_COHERENT) == 0)
2716*61046927SAndroid Build Coastguard Worker return false;
2717*61046927SAndroid Build Coastguard Worker
2718*61046927SAndroid Build Coastguard Worker nir_def *atomic_def = NULL;
2719*61046927SAndroid Build Coastguard Worker b->cursor = nir_before_instr(&intr->instr);
2720*61046927SAndroid Build Coastguard Worker switch (intr->intrinsic) {
2721*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_deref:
2722*61046927SAndroid Build Coastguard Worker case nir_intrinsic_load_ssbo:
2723*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_deref_load:
2724*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_load: {
2725*61046927SAndroid Build Coastguard Worker if (intr->def.bit_size < 32 || intr->def.num_components > 1) {
2726*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_load_deref)
2727*61046927SAndroid Build Coastguard Worker set_deref_variables_coherent(b->shader, nir_src_as_deref(intr->src[0]));
2728*61046927SAndroid Build Coastguard Worker else {
2729*61046927SAndroid Build Coastguard Worker nir_binding binding = {0};
2730*61046927SAndroid Build Coastguard Worker if (nir_src_is_const(intr->src[0]))
2731*61046927SAndroid Build Coastguard Worker binding.binding = nir_src_as_uint(intr->src[0]);
2732*61046927SAndroid Build Coastguard Worker set_binding_variables_coherent(b->shader, binding,
2733*61046927SAndroid Build Coastguard Worker intr->intrinsic == nir_intrinsic_load_ssbo ? nir_var_mem_ssbo : nir_var_image);
2734*61046927SAndroid Build Coastguard Worker }
2735*61046927SAndroid Build Coastguard Worker return false;
2736*61046927SAndroid Build Coastguard Worker }
2737*61046927SAndroid Build Coastguard Worker
2738*61046927SAndroid Build Coastguard Worker atomic_def = get_atomic_for_load_store(b, intr, intr->def.bit_size);
2739*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&intr->def, atomic_def);
2740*61046927SAndroid Build Coastguard Worker break;
2741*61046927SAndroid Build Coastguard Worker }
2742*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_deref:
2743*61046927SAndroid Build Coastguard Worker case nir_intrinsic_store_ssbo:
2744*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_deref_store:
2745*61046927SAndroid Build Coastguard Worker case nir_intrinsic_image_store: {
2746*61046927SAndroid Build Coastguard Worker int resource_idx = intr->intrinsic == nir_intrinsic_store_ssbo ? 1 : 0;
2747*61046927SAndroid Build Coastguard Worker int value_idx = intr->intrinsic == nir_intrinsic_store_ssbo ? 0 :
2748*61046927SAndroid Build Coastguard Worker intr->intrinsic == nir_intrinsic_store_deref ? 1 : 3;
2749*61046927SAndroid Build Coastguard Worker unsigned num_components = nir_intrinsic_has_write_mask(intr) ?
2750*61046927SAndroid Build Coastguard Worker util_bitcount(nir_intrinsic_write_mask(intr)) : intr->src[value_idx].ssa->num_components;
2751*61046927SAndroid Build Coastguard Worker if (intr->src[value_idx].ssa->bit_size < 32 || num_components > 1) {
2752*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_store_deref)
2753*61046927SAndroid Build Coastguard Worker set_deref_variables_coherent(b->shader, nir_src_as_deref(intr->src[resource_idx]));
2754*61046927SAndroid Build Coastguard Worker else {
2755*61046927SAndroid Build Coastguard Worker nir_binding binding = {0};
2756*61046927SAndroid Build Coastguard Worker if (nir_src_is_const(intr->src[resource_idx]))
2757*61046927SAndroid Build Coastguard Worker binding.binding = nir_src_as_uint(intr->src[resource_idx]);
2758*61046927SAndroid Build Coastguard Worker set_binding_variables_coherent(b->shader, binding,
2759*61046927SAndroid Build Coastguard Worker intr->intrinsic == nir_intrinsic_store_ssbo ? nir_var_mem_ssbo : nir_var_image);
2760*61046927SAndroid Build Coastguard Worker }
2761*61046927SAndroid Build Coastguard Worker return false;
2762*61046927SAndroid Build Coastguard Worker }
2763*61046927SAndroid Build Coastguard Worker
2764*61046927SAndroid Build Coastguard Worker atomic_def = get_atomic_for_load_store(b, intr, intr->src[value_idx].ssa->bit_size);
2765*61046927SAndroid Build Coastguard Worker break;
2766*61046927SAndroid Build Coastguard Worker }
2767*61046927SAndroid Build Coastguard Worker default:
2768*61046927SAndroid Build Coastguard Worker return false;
2769*61046927SAndroid Build Coastguard Worker }
2770*61046927SAndroid Build Coastguard Worker
2771*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *atomic = nir_instr_as_intrinsic(atomic_def->parent_instr);
2772*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_access(atomic, nir_intrinsic_access(intr));
2773*61046927SAndroid Build Coastguard Worker if (nir_intrinsic_has_image_dim(intr))
2774*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_image_dim(atomic, nir_intrinsic_image_dim(intr));
2775*61046927SAndroid Build Coastguard Worker if (nir_intrinsic_has_image_array(intr))
2776*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_image_array(atomic, nir_intrinsic_image_array(intr));
2777*61046927SAndroid Build Coastguard Worker if (nir_intrinsic_has_format(intr))
2778*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_format(atomic, nir_intrinsic_format(intr));
2779*61046927SAndroid Build Coastguard Worker if (nir_intrinsic_has_range_base(intr))
2780*61046927SAndroid Build Coastguard Worker nir_intrinsic_set_range_base(atomic, nir_intrinsic_range_base(intr));
2781*61046927SAndroid Build Coastguard Worker nir_instr_remove(&intr->instr);
2782*61046927SAndroid Build Coastguard Worker return true;
2783*61046927SAndroid Build Coastguard Worker }
2784*61046927SAndroid Build Coastguard Worker
2785*61046927SAndroid Build Coastguard Worker bool
dxil_nir_lower_coherent_loads_and_stores(nir_shader * s)2786*61046927SAndroid Build Coastguard Worker dxil_nir_lower_coherent_loads_and_stores(nir_shader *s)
2787*61046927SAndroid Build Coastguard Worker {
2788*61046927SAndroid Build Coastguard Worker return nir_shader_intrinsics_pass(s, lower_coherent_load_store,
2789*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow | nir_metadata_loop_analysis,
2790*61046927SAndroid Build Coastguard Worker NULL);
2791*61046927SAndroid Build Coastguard Worker }
2792*61046927SAndroid Build Coastguard Worker
2793*61046927SAndroid Build Coastguard Worker struct undefined_varying_masks {
2794*61046927SAndroid Build Coastguard Worker uint64_t io_mask;
2795*61046927SAndroid Build Coastguard Worker uint32_t patch_io_mask;
2796*61046927SAndroid Build Coastguard Worker const BITSET_WORD *frac_io_mask;
2797*61046927SAndroid Build Coastguard Worker };
2798*61046927SAndroid Build Coastguard Worker
2799*61046927SAndroid Build Coastguard Worker static bool
is_dead_in_variable(nir_variable * var,void * data)2800*61046927SAndroid Build Coastguard Worker is_dead_in_variable(nir_variable *var, void *data)
2801*61046927SAndroid Build Coastguard Worker {
2802*61046927SAndroid Build Coastguard Worker switch (var->data.location) {
2803*61046927SAndroid Build Coastguard Worker /* Only these values can be system generated values in addition to varyings */
2804*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_PRIMITIVE_ID:
2805*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_FACE:
2806*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_VIEW_INDEX:
2807*61046927SAndroid Build Coastguard Worker return false;
2808*61046927SAndroid Build Coastguard Worker /* Tessellation input vars must remain untouched */
2809*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_TESS_LEVEL_INNER:
2810*61046927SAndroid Build Coastguard Worker case VARYING_SLOT_TESS_LEVEL_OUTER:
2811*61046927SAndroid Build Coastguard Worker return false;
2812*61046927SAndroid Build Coastguard Worker default:
2813*61046927SAndroid Build Coastguard Worker return true;
2814*61046927SAndroid Build Coastguard Worker }
2815*61046927SAndroid Build Coastguard Worker }
2816*61046927SAndroid Build Coastguard Worker
2817*61046927SAndroid Build Coastguard Worker static bool
kill_undefined_varyings(struct nir_builder * b,nir_instr * instr,void * data)2818*61046927SAndroid Build Coastguard Worker kill_undefined_varyings(struct nir_builder *b,
2819*61046927SAndroid Build Coastguard Worker nir_instr *instr,
2820*61046927SAndroid Build Coastguard Worker void *data)
2821*61046927SAndroid Build Coastguard Worker {
2822*61046927SAndroid Build Coastguard Worker const struct undefined_varying_masks *masks = data;
2823*61046927SAndroid Build Coastguard Worker
2824*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_intrinsic)
2825*61046927SAndroid Build Coastguard Worker return false;
2826*61046927SAndroid Build Coastguard Worker
2827*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
2828*61046927SAndroid Build Coastguard Worker
2829*61046927SAndroid Build Coastguard Worker if (intr->intrinsic != nir_intrinsic_load_deref)
2830*61046927SAndroid Build Coastguard Worker return false;
2831*61046927SAndroid Build Coastguard Worker
2832*61046927SAndroid Build Coastguard Worker nir_variable *var = nir_intrinsic_get_var(intr, 0);
2833*61046927SAndroid Build Coastguard Worker if (!var || var->data.mode != nir_var_shader_in)
2834*61046927SAndroid Build Coastguard Worker return false;
2835*61046927SAndroid Build Coastguard Worker
2836*61046927SAndroid Build Coastguard Worker if (!is_dead_in_variable(var, NULL))
2837*61046927SAndroid Build Coastguard Worker return false;
2838*61046927SAndroid Build Coastguard Worker
2839*61046927SAndroid Build Coastguard Worker uint32_t loc = var->data.patch && var->data.location >= VARYING_SLOT_PATCH0 ?
2840*61046927SAndroid Build Coastguard Worker var->data.location - VARYING_SLOT_PATCH0 :
2841*61046927SAndroid Build Coastguard Worker var->data.location;
2842*61046927SAndroid Build Coastguard Worker uint64_t written = var->data.patch && var->data.location >= VARYING_SLOT_PATCH0 ?
2843*61046927SAndroid Build Coastguard Worker masks->patch_io_mask : masks->io_mask;
2844*61046927SAndroid Build Coastguard Worker if (BITFIELD64_RANGE(loc, glsl_varying_count(var->type)) & written) {
2845*61046927SAndroid Build Coastguard Worker if (!masks->frac_io_mask || !var->data.location_frac ||
2846*61046927SAndroid Build Coastguard Worker var->data.location < VARYING_SLOT_VAR0 ||
2847*61046927SAndroid Build Coastguard Worker BITSET_TEST(masks->frac_io_mask, (var->data.location - VARYING_SLOT_VAR0) * 4 + var->data.location_frac))
2848*61046927SAndroid Build Coastguard Worker return false;
2849*61046927SAndroid Build Coastguard Worker }
2850*61046927SAndroid Build Coastguard Worker
2851*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(instr);
2852*61046927SAndroid Build Coastguard Worker /* Note: zero is used instead of undef, because optimization is not run here, but is
2853*61046927SAndroid Build Coastguard Worker * run later on. If we load an undef here, and that undef ends up being used to store
2854*61046927SAndroid Build Coastguard Worker * to position later on, that can cause some or all of the components in that position
2855*61046927SAndroid Build Coastguard Worker * write to be removed, which is problematic especially in the case of all components,
2856*61046927SAndroid Build Coastguard Worker * since that would remove the store instruction, and would make it tricky to satisfy
2857*61046927SAndroid Build Coastguard Worker * the DXIL requirements of writing all position components.
2858*61046927SAndroid Build Coastguard Worker */
2859*61046927SAndroid Build Coastguard Worker nir_def *zero = nir_imm_zero(b, intr->def.num_components,
2860*61046927SAndroid Build Coastguard Worker intr->def.bit_size);
2861*61046927SAndroid Build Coastguard Worker nir_def_replace(&intr->def, zero);
2862*61046927SAndroid Build Coastguard Worker return true;
2863*61046927SAndroid Build Coastguard Worker }
2864*61046927SAndroid Build Coastguard Worker
2865*61046927SAndroid Build Coastguard Worker bool
dxil_nir_kill_undefined_varyings(nir_shader * shader,uint64_t prev_stage_written_mask,uint32_t prev_stage_patch_written_mask,const BITSET_WORD * prev_stage_frac_output_mask)2866*61046927SAndroid Build Coastguard Worker dxil_nir_kill_undefined_varyings(nir_shader *shader, uint64_t prev_stage_written_mask, uint32_t prev_stage_patch_written_mask,
2867*61046927SAndroid Build Coastguard Worker const BITSET_WORD *prev_stage_frac_output_mask)
2868*61046927SAndroid Build Coastguard Worker {
2869*61046927SAndroid Build Coastguard Worker struct undefined_varying_masks masks = {
2870*61046927SAndroid Build Coastguard Worker .io_mask = prev_stage_written_mask,
2871*61046927SAndroid Build Coastguard Worker .patch_io_mask = prev_stage_patch_written_mask,
2872*61046927SAndroid Build Coastguard Worker .frac_io_mask = prev_stage_frac_output_mask
2873*61046927SAndroid Build Coastguard Worker };
2874*61046927SAndroid Build Coastguard Worker bool progress = nir_shader_instructions_pass(shader,
2875*61046927SAndroid Build Coastguard Worker kill_undefined_varyings,
2876*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow |
2877*61046927SAndroid Build Coastguard Worker nir_metadata_loop_analysis,
2878*61046927SAndroid Build Coastguard Worker (void *)&masks);
2879*61046927SAndroid Build Coastguard Worker if (progress) {
2880*61046927SAndroid Build Coastguard Worker nir_opt_dce(shader);
2881*61046927SAndroid Build Coastguard Worker nir_remove_dead_derefs(shader);
2882*61046927SAndroid Build Coastguard Worker }
2883*61046927SAndroid Build Coastguard Worker
2884*61046927SAndroid Build Coastguard Worker const struct nir_remove_dead_variables_options options = {
2885*61046927SAndroid Build Coastguard Worker .can_remove_var = is_dead_in_variable,
2886*61046927SAndroid Build Coastguard Worker .can_remove_var_data = &masks,
2887*61046927SAndroid Build Coastguard Worker };
2888*61046927SAndroid Build Coastguard Worker progress |= nir_remove_dead_variables(shader, nir_var_shader_in, &options);
2889*61046927SAndroid Build Coastguard Worker return progress;
2890*61046927SAndroid Build Coastguard Worker }
2891*61046927SAndroid Build Coastguard Worker
2892*61046927SAndroid Build Coastguard Worker static bool
is_dead_out_variable(nir_variable * var,void * data)2893*61046927SAndroid Build Coastguard Worker is_dead_out_variable(nir_variable *var, void *data)
2894*61046927SAndroid Build Coastguard Worker {
2895*61046927SAndroid Build Coastguard Worker return !nir_slot_is_sysval_output(var->data.location, MESA_SHADER_NONE);
2896*61046927SAndroid Build Coastguard Worker }
2897*61046927SAndroid Build Coastguard Worker
2898*61046927SAndroid Build Coastguard Worker static bool
kill_unused_outputs(struct nir_builder * b,nir_instr * instr,void * data)2899*61046927SAndroid Build Coastguard Worker kill_unused_outputs(struct nir_builder *b,
2900*61046927SAndroid Build Coastguard Worker nir_instr *instr,
2901*61046927SAndroid Build Coastguard Worker void *data)
2902*61046927SAndroid Build Coastguard Worker {
2903*61046927SAndroid Build Coastguard Worker const struct undefined_varying_masks *masks = data;
2904*61046927SAndroid Build Coastguard Worker
2905*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_intrinsic)
2906*61046927SAndroid Build Coastguard Worker return false;
2907*61046927SAndroid Build Coastguard Worker
2908*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
2909*61046927SAndroid Build Coastguard Worker
2910*61046927SAndroid Build Coastguard Worker if (intr->intrinsic != nir_intrinsic_store_deref &&
2911*61046927SAndroid Build Coastguard Worker intr->intrinsic != nir_intrinsic_load_deref)
2912*61046927SAndroid Build Coastguard Worker return false;
2913*61046927SAndroid Build Coastguard Worker
2914*61046927SAndroid Build Coastguard Worker nir_variable *var = nir_intrinsic_get_var(intr, 0);
2915*61046927SAndroid Build Coastguard Worker if (!var || var->data.mode != nir_var_shader_out ||
2916*61046927SAndroid Build Coastguard Worker /* always_active_io can mean two things: xfb or GL separable shaders. We can't delete
2917*61046927SAndroid Build Coastguard Worker * varyings that are used for xfb (we'll just sort them last), but we must delete varyings
2918*61046927SAndroid Build Coastguard Worker * that are mismatching between TCS and TES. Fortunately TCS can't do xfb, so we can ignore
2919*61046927SAndroid Build Coastguard Worker the always_active_io bit for TCS outputs. */
2920*61046927SAndroid Build Coastguard Worker (b->shader->info.stage != MESA_SHADER_TESS_CTRL && var->data.always_active_io))
2921*61046927SAndroid Build Coastguard Worker return false;
2922*61046927SAndroid Build Coastguard Worker
2923*61046927SAndroid Build Coastguard Worker if (!is_dead_out_variable(var, NULL))
2924*61046927SAndroid Build Coastguard Worker return false;
2925*61046927SAndroid Build Coastguard Worker
2926*61046927SAndroid Build Coastguard Worker unsigned loc = var->data.patch && var->data.location >= VARYING_SLOT_PATCH0 ?
2927*61046927SAndroid Build Coastguard Worker var->data.location - VARYING_SLOT_PATCH0 :
2928*61046927SAndroid Build Coastguard Worker var->data.location;
2929*61046927SAndroid Build Coastguard Worker uint64_t read = var->data.patch && var->data.location >= VARYING_SLOT_PATCH0 ?
2930*61046927SAndroid Build Coastguard Worker masks->patch_io_mask : masks->io_mask;
2931*61046927SAndroid Build Coastguard Worker if (BITFIELD64_RANGE(loc, glsl_varying_count(var->type)) & read) {
2932*61046927SAndroid Build Coastguard Worker if (!masks->frac_io_mask || !var->data.location_frac ||
2933*61046927SAndroid Build Coastguard Worker var->data.location < VARYING_SLOT_VAR0 ||
2934*61046927SAndroid Build Coastguard Worker BITSET_TEST(masks->frac_io_mask, (var->data.location - VARYING_SLOT_VAR0) * 4 + var->data.location_frac))
2935*61046927SAndroid Build Coastguard Worker return false;
2936*61046927SAndroid Build Coastguard Worker }
2937*61046927SAndroid Build Coastguard Worker
2938*61046927SAndroid Build Coastguard Worker if (intr->intrinsic == nir_intrinsic_load_deref) {
2939*61046927SAndroid Build Coastguard Worker b->cursor = nir_after_instr(&intr->instr);
2940*61046927SAndroid Build Coastguard Worker nir_def *zero = nir_imm_zero(b, intr->def.num_components, intr->def.bit_size);
2941*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&intr->def, zero);
2942*61046927SAndroid Build Coastguard Worker }
2943*61046927SAndroid Build Coastguard Worker nir_instr_remove(instr);
2944*61046927SAndroid Build Coastguard Worker return true;
2945*61046927SAndroid Build Coastguard Worker }
2946*61046927SAndroid Build Coastguard Worker
2947*61046927SAndroid Build Coastguard Worker bool
dxil_nir_kill_unused_outputs(nir_shader * shader,uint64_t next_stage_read_mask,uint32_t next_stage_patch_read_mask,const BITSET_WORD * next_stage_frac_input_mask)2948*61046927SAndroid Build Coastguard Worker dxil_nir_kill_unused_outputs(nir_shader *shader, uint64_t next_stage_read_mask, uint32_t next_stage_patch_read_mask,
2949*61046927SAndroid Build Coastguard Worker const BITSET_WORD *next_stage_frac_input_mask)
2950*61046927SAndroid Build Coastguard Worker {
2951*61046927SAndroid Build Coastguard Worker struct undefined_varying_masks masks = {
2952*61046927SAndroid Build Coastguard Worker .io_mask = next_stage_read_mask,
2953*61046927SAndroid Build Coastguard Worker .patch_io_mask = next_stage_patch_read_mask,
2954*61046927SAndroid Build Coastguard Worker .frac_io_mask = next_stage_frac_input_mask
2955*61046927SAndroid Build Coastguard Worker };
2956*61046927SAndroid Build Coastguard Worker
2957*61046927SAndroid Build Coastguard Worker bool progress = nir_shader_instructions_pass(shader,
2958*61046927SAndroid Build Coastguard Worker kill_unused_outputs,
2959*61046927SAndroid Build Coastguard Worker nir_metadata_control_flow |
2960*61046927SAndroid Build Coastguard Worker nir_metadata_loop_analysis,
2961*61046927SAndroid Build Coastguard Worker (void *)&masks);
2962*61046927SAndroid Build Coastguard Worker
2963*61046927SAndroid Build Coastguard Worker if (progress) {
2964*61046927SAndroid Build Coastguard Worker nir_opt_dce(shader);
2965*61046927SAndroid Build Coastguard Worker nir_remove_dead_derefs(shader);
2966*61046927SAndroid Build Coastguard Worker }
2967*61046927SAndroid Build Coastguard Worker const struct nir_remove_dead_variables_options options = {
2968*61046927SAndroid Build Coastguard Worker .can_remove_var = is_dead_out_variable,
2969*61046927SAndroid Build Coastguard Worker .can_remove_var_data = &masks,
2970*61046927SAndroid Build Coastguard Worker };
2971*61046927SAndroid Build Coastguard Worker progress |= nir_remove_dead_variables(shader, nir_var_shader_out, &options);
2972*61046927SAndroid Build Coastguard Worker return progress;
2973*61046927SAndroid Build Coastguard Worker }
2974