xref: /aosp_15_r20/external/mesa3d/src/compiler/spirv/vtn_cfg.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright © 2015 Intel 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 "vtn_private.h"
25*61046927SAndroid Build Coastguard Worker #include "spirv_info.h"
26*61046927SAndroid Build Coastguard Worker #include "nir/nir_vla.h"
27*61046927SAndroid Build Coastguard Worker #include "util/u_debug.h"
28*61046927SAndroid Build Coastguard Worker 
29*61046927SAndroid Build Coastguard Worker static unsigned
glsl_type_count_function_params(const struct glsl_type * type)30*61046927SAndroid Build Coastguard Worker glsl_type_count_function_params(const struct glsl_type *type)
31*61046927SAndroid Build Coastguard Worker {
32*61046927SAndroid Build Coastguard Worker    if (glsl_type_is_vector_or_scalar(type)) {
33*61046927SAndroid Build Coastguard Worker       return 1;
34*61046927SAndroid Build Coastguard Worker    } else if (glsl_type_is_array_or_matrix(type)) {
35*61046927SAndroid Build Coastguard Worker       return glsl_get_length(type) *
36*61046927SAndroid Build Coastguard Worker              glsl_type_count_function_params(glsl_get_array_element(type));
37*61046927SAndroid Build Coastguard Worker    } else {
38*61046927SAndroid Build Coastguard Worker       assert(glsl_type_is_struct_or_ifc(type));
39*61046927SAndroid Build Coastguard Worker       unsigned count = 0;
40*61046927SAndroid Build Coastguard Worker       unsigned elems = glsl_get_length(type);
41*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < elems; i++) {
42*61046927SAndroid Build Coastguard Worker          const struct glsl_type *elem_type = glsl_get_struct_field(type, i);
43*61046927SAndroid Build Coastguard Worker          count += glsl_type_count_function_params(elem_type);
44*61046927SAndroid Build Coastguard Worker       }
45*61046927SAndroid Build Coastguard Worker       return count;
46*61046927SAndroid Build Coastguard Worker    }
47*61046927SAndroid Build Coastguard Worker }
48*61046927SAndroid Build Coastguard Worker 
49*61046927SAndroid Build Coastguard Worker static void
glsl_type_add_to_function_params(const struct glsl_type * type,nir_function * func,unsigned * param_idx)50*61046927SAndroid Build Coastguard Worker glsl_type_add_to_function_params(const struct glsl_type *type,
51*61046927SAndroid Build Coastguard Worker                                  nir_function *func,
52*61046927SAndroid Build Coastguard Worker                                  unsigned *param_idx)
53*61046927SAndroid Build Coastguard Worker {
54*61046927SAndroid Build Coastguard Worker    if (glsl_type_is_vector_or_scalar(type)) {
55*61046927SAndroid Build Coastguard Worker       func->params[(*param_idx)++] = (nir_parameter) {
56*61046927SAndroid Build Coastguard Worker          .num_components = glsl_get_vector_elements(type),
57*61046927SAndroid Build Coastguard Worker          .bit_size = glsl_get_bit_size(type),
58*61046927SAndroid Build Coastguard Worker       };
59*61046927SAndroid Build Coastguard Worker    } else if (glsl_type_is_array_or_matrix(type)) {
60*61046927SAndroid Build Coastguard Worker       unsigned elems = glsl_get_length(type);
61*61046927SAndroid Build Coastguard Worker       const struct glsl_type *elem_type = glsl_get_array_element(type);
62*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < elems; i++)
63*61046927SAndroid Build Coastguard Worker          glsl_type_add_to_function_params(elem_type,func, param_idx);
64*61046927SAndroid Build Coastguard Worker    } else {
65*61046927SAndroid Build Coastguard Worker       assert(glsl_type_is_struct_or_ifc(type));
66*61046927SAndroid Build Coastguard Worker       unsigned elems = glsl_get_length(type);
67*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < elems; i++) {
68*61046927SAndroid Build Coastguard Worker          const struct glsl_type *elem_type = glsl_get_struct_field(type, i);
69*61046927SAndroid Build Coastguard Worker          glsl_type_add_to_function_params(elem_type, func, param_idx);
70*61046927SAndroid Build Coastguard Worker       }
71*61046927SAndroid Build Coastguard Worker    }
72*61046927SAndroid Build Coastguard Worker }
73*61046927SAndroid Build Coastguard Worker 
74*61046927SAndroid Build Coastguard Worker static void
vtn_ssa_value_add_to_call_params(struct vtn_builder * b,struct vtn_ssa_value * value,nir_call_instr * call,unsigned * param_idx)75*61046927SAndroid Build Coastguard Worker vtn_ssa_value_add_to_call_params(struct vtn_builder *b,
76*61046927SAndroid Build Coastguard Worker                                  struct vtn_ssa_value *value,
77*61046927SAndroid Build Coastguard Worker                                  nir_call_instr *call,
78*61046927SAndroid Build Coastguard Worker                                  unsigned *param_idx)
79*61046927SAndroid Build Coastguard Worker {
80*61046927SAndroid Build Coastguard Worker    if (glsl_type_is_vector_or_scalar(value->type)) {
81*61046927SAndroid Build Coastguard Worker       call->params[(*param_idx)++] = nir_src_for_ssa(value->def);
82*61046927SAndroid Build Coastguard Worker    } else {
83*61046927SAndroid Build Coastguard Worker       unsigned elems = glsl_get_length(value->type);
84*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < elems; i++) {
85*61046927SAndroid Build Coastguard Worker          vtn_ssa_value_add_to_call_params(b, value->elems[i],
86*61046927SAndroid Build Coastguard Worker                                           call, param_idx);
87*61046927SAndroid Build Coastguard Worker       }
88*61046927SAndroid Build Coastguard Worker    }
89*61046927SAndroid Build Coastguard Worker }
90*61046927SAndroid Build Coastguard Worker 
91*61046927SAndroid Build Coastguard Worker struct vtn_func_arg_info {
92*61046927SAndroid Build Coastguard Worker    bool by_value;
93*61046927SAndroid Build Coastguard Worker };
94*61046927SAndroid Build Coastguard Worker 
95*61046927SAndroid Build Coastguard Worker static void
function_parameter_decoration_cb(struct vtn_builder * b,struct vtn_value * val,int member,const struct vtn_decoration * dec,void * arg_info)96*61046927SAndroid Build Coastguard Worker function_parameter_decoration_cb(struct vtn_builder *b, struct vtn_value *val,
97*61046927SAndroid Build Coastguard Worker                                  int member, const struct vtn_decoration *dec,
98*61046927SAndroid Build Coastguard Worker                                  void *arg_info)
99*61046927SAndroid Build Coastguard Worker {
100*61046927SAndroid Build Coastguard Worker    struct vtn_func_arg_info *info = arg_info;
101*61046927SAndroid Build Coastguard Worker 
102*61046927SAndroid Build Coastguard Worker    switch (dec->decoration) {
103*61046927SAndroid Build Coastguard Worker    case SpvDecorationFuncParamAttr:
104*61046927SAndroid Build Coastguard Worker       for (uint32_t i = 0; i < dec->num_operands; i++) {
105*61046927SAndroid Build Coastguard Worker          uint32_t attr = dec->operands[i];
106*61046927SAndroid Build Coastguard Worker          switch (attr) {
107*61046927SAndroid Build Coastguard Worker          /* ignore for now */
108*61046927SAndroid Build Coastguard Worker          case SpvFunctionParameterAttributeNoAlias:
109*61046927SAndroid Build Coastguard Worker          case SpvFunctionParameterAttributeSext:
110*61046927SAndroid Build Coastguard Worker          case SpvFunctionParameterAttributeZext:
111*61046927SAndroid Build Coastguard Worker             break;
112*61046927SAndroid Build Coastguard Worker 
113*61046927SAndroid Build Coastguard Worker          case SpvFunctionParameterAttributeByVal:
114*61046927SAndroid Build Coastguard Worker             info->by_value = true;
115*61046927SAndroid Build Coastguard Worker             break;
116*61046927SAndroid Build Coastguard Worker 
117*61046927SAndroid Build Coastguard Worker          default:
118*61046927SAndroid Build Coastguard Worker             vtn_warn("Function parameter Decoration not handled: %s",
119*61046927SAndroid Build Coastguard Worker                      spirv_functionparameterattribute_to_string(attr));
120*61046927SAndroid Build Coastguard Worker             break;
121*61046927SAndroid Build Coastguard Worker          }
122*61046927SAndroid Build Coastguard Worker       }
123*61046927SAndroid Build Coastguard Worker       break;
124*61046927SAndroid Build Coastguard Worker 
125*61046927SAndroid Build Coastguard Worker    /* ignore for now */
126*61046927SAndroid Build Coastguard Worker    case SpvDecorationAliased:
127*61046927SAndroid Build Coastguard Worker    case SpvDecorationAliasedPointer:
128*61046927SAndroid Build Coastguard Worker    case SpvDecorationAlignment:
129*61046927SAndroid Build Coastguard Worker    case SpvDecorationRelaxedPrecision:
130*61046927SAndroid Build Coastguard Worker    case SpvDecorationRestrict:
131*61046927SAndroid Build Coastguard Worker    case SpvDecorationRestrictPointer:
132*61046927SAndroid Build Coastguard Worker    case SpvDecorationVolatile:
133*61046927SAndroid Build Coastguard Worker       break;
134*61046927SAndroid Build Coastguard Worker 
135*61046927SAndroid Build Coastguard Worker    default:
136*61046927SAndroid Build Coastguard Worker       vtn_warn("Function parameter Decoration not handled: %s",
137*61046927SAndroid Build Coastguard Worker                spirv_decoration_to_string(dec->decoration));
138*61046927SAndroid Build Coastguard Worker       break;
139*61046927SAndroid Build Coastguard Worker    }
140*61046927SAndroid Build Coastguard Worker }
141*61046927SAndroid Build Coastguard Worker 
142*61046927SAndroid Build Coastguard Worker static void
vtn_ssa_value_load_function_param(struct vtn_builder * b,struct vtn_ssa_value * value,struct vtn_type * type,struct vtn_func_arg_info * info,unsigned * param_idx)143*61046927SAndroid Build Coastguard Worker vtn_ssa_value_load_function_param(struct vtn_builder *b,
144*61046927SAndroid Build Coastguard Worker                                   struct vtn_ssa_value *value,
145*61046927SAndroid Build Coastguard Worker                                   struct vtn_type *type,
146*61046927SAndroid Build Coastguard Worker                                   struct vtn_func_arg_info *info,
147*61046927SAndroid Build Coastguard Worker                                   unsigned *param_idx)
148*61046927SAndroid Build Coastguard Worker {
149*61046927SAndroid Build Coastguard Worker    if (glsl_type_is_vector_or_scalar(value->type)) {
150*61046927SAndroid Build Coastguard Worker       /* if the parameter is passed by value, we need to create a local copy if it's a pointer */
151*61046927SAndroid Build Coastguard Worker       if (info->by_value && type && type->base_type == vtn_base_type_pointer) {
152*61046927SAndroid Build Coastguard Worker          struct vtn_type *pointee_type = type->pointed;
153*61046927SAndroid Build Coastguard Worker 
154*61046927SAndroid Build Coastguard Worker          nir_variable *copy =
155*61046927SAndroid Build Coastguard Worker             nir_local_variable_create(b->nb.impl, pointee_type->type, NULL);
156*61046927SAndroid Build Coastguard Worker 
157*61046927SAndroid Build Coastguard Worker          nir_variable_mode mode;
158*61046927SAndroid Build Coastguard Worker          vtn_storage_class_to_mode(b, type->storage_class, NULL, &mode);
159*61046927SAndroid Build Coastguard Worker 
160*61046927SAndroid Build Coastguard Worker          nir_def *param = nir_load_param(&b->nb, (*param_idx)++);
161*61046927SAndroid Build Coastguard Worker          nir_deref_instr *src = nir_build_deref_cast(&b->nb, param, mode, copy->type, 0);
162*61046927SAndroid Build Coastguard Worker          nir_deref_instr *dst = nir_build_deref_var(&b->nb, copy);
163*61046927SAndroid Build Coastguard Worker 
164*61046927SAndroid Build Coastguard Worker          nir_copy_deref(&b->nb, dst, src);
165*61046927SAndroid Build Coastguard Worker 
166*61046927SAndroid Build Coastguard Worker          nir_deref_instr *load =
167*61046927SAndroid Build Coastguard Worker             nir_build_deref_cast(&b->nb, &dst->def, nir_var_function_temp, type->type, 0);
168*61046927SAndroid Build Coastguard Worker          value->def = &load->def;
169*61046927SAndroid Build Coastguard Worker       } else {
170*61046927SAndroid Build Coastguard Worker          value->def = nir_load_param(&b->nb, (*param_idx)++);
171*61046927SAndroid Build Coastguard Worker       }
172*61046927SAndroid Build Coastguard Worker    } else {
173*61046927SAndroid Build Coastguard Worker       unsigned elems = glsl_get_length(value->type);
174*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < elems; i++)
175*61046927SAndroid Build Coastguard Worker          vtn_ssa_value_load_function_param(b, value->elems[i], NULL, info, param_idx);
176*61046927SAndroid Build Coastguard Worker    }
177*61046927SAndroid Build Coastguard Worker }
178*61046927SAndroid Build Coastguard Worker 
179*61046927SAndroid Build Coastguard Worker void
vtn_handle_function_call(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)180*61046927SAndroid Build Coastguard Worker vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode,
181*61046927SAndroid Build Coastguard Worker                          const uint32_t *w, unsigned count)
182*61046927SAndroid Build Coastguard Worker {
183*61046927SAndroid Build Coastguard Worker    struct vtn_function *vtn_callee =
184*61046927SAndroid Build Coastguard Worker       vtn_value(b, w[3], vtn_value_type_function)->func;
185*61046927SAndroid Build Coastguard Worker 
186*61046927SAndroid Build Coastguard Worker    vtn_callee->referenced = true;
187*61046927SAndroid Build Coastguard Worker 
188*61046927SAndroid Build Coastguard Worker    nir_call_instr *call = nir_call_instr_create(b->nb.shader,
189*61046927SAndroid Build Coastguard Worker                                                 vtn_callee->nir_func);
190*61046927SAndroid Build Coastguard Worker 
191*61046927SAndroid Build Coastguard Worker    unsigned param_idx = 0;
192*61046927SAndroid Build Coastguard Worker 
193*61046927SAndroid Build Coastguard Worker    nir_deref_instr *ret_deref = NULL;
194*61046927SAndroid Build Coastguard Worker    struct vtn_type *ret_type = vtn_callee->type->return_type;
195*61046927SAndroid Build Coastguard Worker    if (ret_type->base_type != vtn_base_type_void) {
196*61046927SAndroid Build Coastguard Worker       nir_variable *ret_tmp =
197*61046927SAndroid Build Coastguard Worker          nir_local_variable_create(b->nb.impl,
198*61046927SAndroid Build Coastguard Worker                                    glsl_get_bare_type(ret_type->type),
199*61046927SAndroid Build Coastguard Worker                                    "return_tmp");
200*61046927SAndroid Build Coastguard Worker       ret_deref = nir_build_deref_var(&b->nb, ret_tmp);
201*61046927SAndroid Build Coastguard Worker       call->params[param_idx++] = nir_src_for_ssa(&ret_deref->def);
202*61046927SAndroid Build Coastguard Worker    }
203*61046927SAndroid Build Coastguard Worker 
204*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < vtn_callee->type->length; i++) {
205*61046927SAndroid Build Coastguard Worker       vtn_ssa_value_add_to_call_params(b, vtn_ssa_value(b, w[4 + i]),
206*61046927SAndroid Build Coastguard Worker                                        call, &param_idx);
207*61046927SAndroid Build Coastguard Worker    }
208*61046927SAndroid Build Coastguard Worker    assert(param_idx == call->num_params);
209*61046927SAndroid Build Coastguard Worker 
210*61046927SAndroid Build Coastguard Worker    nir_builder_instr_insert(&b->nb, &call->instr);
211*61046927SAndroid Build Coastguard Worker 
212*61046927SAndroid Build Coastguard Worker    if (ret_type->base_type == vtn_base_type_void) {
213*61046927SAndroid Build Coastguard Worker       vtn_push_value(b, w[2], vtn_value_type_undef);
214*61046927SAndroid Build Coastguard Worker    } else {
215*61046927SAndroid Build Coastguard Worker       vtn_push_ssa_value(b, w[2], vtn_local_load(b, ret_deref, 0));
216*61046927SAndroid Build Coastguard Worker    }
217*61046927SAndroid Build Coastguard Worker }
218*61046927SAndroid Build Coastguard Worker 
219*61046927SAndroid Build Coastguard Worker static void
function_decoration_cb(struct vtn_builder * b,struct vtn_value * val,int member,const struct vtn_decoration * dec,void * void_func)220*61046927SAndroid Build Coastguard Worker function_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member,
221*61046927SAndroid Build Coastguard Worker                        const struct vtn_decoration *dec, void *void_func)
222*61046927SAndroid Build Coastguard Worker {
223*61046927SAndroid Build Coastguard Worker    struct vtn_function *func = void_func;
224*61046927SAndroid Build Coastguard Worker 
225*61046927SAndroid Build Coastguard Worker    switch (dec->decoration) {
226*61046927SAndroid Build Coastguard Worker    case SpvDecorationLinkageAttributes: {
227*61046927SAndroid Build Coastguard Worker       unsigned name_words;
228*61046927SAndroid Build Coastguard Worker       const char *name =
229*61046927SAndroid Build Coastguard Worker          vtn_string_literal(b, dec->operands, dec->num_operands, &name_words);
230*61046927SAndroid Build Coastguard Worker       vtn_fail_if(name_words >= dec->num_operands,
231*61046927SAndroid Build Coastguard Worker                   "Malformed LinkageAttributes decoration");
232*61046927SAndroid Build Coastguard Worker       (void)name; /* TODO: What is this? */
233*61046927SAndroid Build Coastguard Worker       func->linkage = dec->operands[name_words];
234*61046927SAndroid Build Coastguard Worker       break;
235*61046927SAndroid Build Coastguard Worker    }
236*61046927SAndroid Build Coastguard Worker 
237*61046927SAndroid Build Coastguard Worker    default:
238*61046927SAndroid Build Coastguard Worker       break;
239*61046927SAndroid Build Coastguard Worker    }
240*61046927SAndroid Build Coastguard Worker }
241*61046927SAndroid Build Coastguard Worker 
242*61046927SAndroid Build Coastguard Worker bool
vtn_cfg_handle_prepass_instruction(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)243*61046927SAndroid Build Coastguard Worker vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode,
244*61046927SAndroid Build Coastguard Worker                                    const uint32_t *w, unsigned count)
245*61046927SAndroid Build Coastguard Worker {
246*61046927SAndroid Build Coastguard Worker    switch (opcode) {
247*61046927SAndroid Build Coastguard Worker    case SpvOpFunction: {
248*61046927SAndroid Build Coastguard Worker       vtn_assert(b->func == NULL);
249*61046927SAndroid Build Coastguard Worker       b->func = vtn_zalloc(b, struct vtn_function);
250*61046927SAndroid Build Coastguard Worker 
251*61046927SAndroid Build Coastguard Worker       list_inithead(&b->func->body);
252*61046927SAndroid Build Coastguard Worker       b->func->linkage = SpvLinkageTypeMax;
253*61046927SAndroid Build Coastguard Worker       b->func->control = w[3];
254*61046927SAndroid Build Coastguard Worker       list_inithead(&b->func->constructs);
255*61046927SAndroid Build Coastguard Worker 
256*61046927SAndroid Build Coastguard Worker       UNUSED const struct glsl_type *result_type = vtn_get_type(b, w[1])->type;
257*61046927SAndroid Build Coastguard Worker       struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_function);
258*61046927SAndroid Build Coastguard Worker       val->func = b->func;
259*61046927SAndroid Build Coastguard Worker 
260*61046927SAndroid Build Coastguard Worker       vtn_foreach_decoration(b, val, function_decoration_cb, b->func);
261*61046927SAndroid Build Coastguard Worker 
262*61046927SAndroid Build Coastguard Worker       b->func->type = vtn_get_type(b, w[4]);
263*61046927SAndroid Build Coastguard Worker       const struct vtn_type *func_type = b->func->type;
264*61046927SAndroid Build Coastguard Worker 
265*61046927SAndroid Build Coastguard Worker       vtn_assert(func_type->return_type->type == result_type);
266*61046927SAndroid Build Coastguard Worker 
267*61046927SAndroid Build Coastguard Worker       nir_function *func =
268*61046927SAndroid Build Coastguard Worker          nir_function_create(b->shader, ralloc_strdup(b->shader, val->name));
269*61046927SAndroid Build Coastguard Worker 
270*61046927SAndroid Build Coastguard Worker       unsigned num_params = 0;
271*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < func_type->length; i++)
272*61046927SAndroid Build Coastguard Worker          num_params += glsl_type_count_function_params(func_type->params[i]->type);
273*61046927SAndroid Build Coastguard Worker 
274*61046927SAndroid Build Coastguard Worker       /* Add one parameter for the function return value */
275*61046927SAndroid Build Coastguard Worker       if (func_type->return_type->base_type != vtn_base_type_void)
276*61046927SAndroid Build Coastguard Worker          num_params++;
277*61046927SAndroid Build Coastguard Worker 
278*61046927SAndroid Build Coastguard Worker       func->should_inline = b->func->control & SpvFunctionControlInlineMask;
279*61046927SAndroid Build Coastguard Worker       func->dont_inline = b->func->control & SpvFunctionControlDontInlineMask;
280*61046927SAndroid Build Coastguard Worker       func->is_exported = b->func->linkage == SpvLinkageTypeExport;
281*61046927SAndroid Build Coastguard Worker 
282*61046927SAndroid Build Coastguard Worker       func->num_params = num_params;
283*61046927SAndroid Build Coastguard Worker       func->params = ralloc_array(b->shader, nir_parameter, num_params);
284*61046927SAndroid Build Coastguard Worker 
285*61046927SAndroid Build Coastguard Worker       unsigned idx = 0;
286*61046927SAndroid Build Coastguard Worker       if (func_type->return_type->base_type != vtn_base_type_void) {
287*61046927SAndroid Build Coastguard Worker          nir_address_format addr_format =
288*61046927SAndroid Build Coastguard Worker             vtn_mode_to_address_format(b, vtn_variable_mode_function);
289*61046927SAndroid Build Coastguard Worker          /* The return value is a regular pointer */
290*61046927SAndroid Build Coastguard Worker          func->params[idx++] = (nir_parameter) {
291*61046927SAndroid Build Coastguard Worker             .num_components = nir_address_format_num_components(addr_format),
292*61046927SAndroid Build Coastguard Worker             .bit_size = nir_address_format_bit_size(addr_format),
293*61046927SAndroid Build Coastguard Worker          };
294*61046927SAndroid Build Coastguard Worker       }
295*61046927SAndroid Build Coastguard Worker 
296*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < func_type->length; i++)
297*61046927SAndroid Build Coastguard Worker          glsl_type_add_to_function_params(func_type->params[i]->type, func, &idx);
298*61046927SAndroid Build Coastguard Worker       assert(idx == num_params);
299*61046927SAndroid Build Coastguard Worker 
300*61046927SAndroid Build Coastguard Worker       b->func->nir_func = func;
301*61046927SAndroid Build Coastguard Worker 
302*61046927SAndroid Build Coastguard Worker       /* Set up a nir_function_impl and the builder so we can load arguments
303*61046927SAndroid Build Coastguard Worker        * directly in our OpFunctionParameter handler.
304*61046927SAndroid Build Coastguard Worker        */
305*61046927SAndroid Build Coastguard Worker       nir_function_impl *impl = nir_function_impl_create(func);
306*61046927SAndroid Build Coastguard Worker       b->nb = nir_builder_at(nir_before_impl(impl));
307*61046927SAndroid Build Coastguard Worker       b->nb.exact = b->exact;
308*61046927SAndroid Build Coastguard Worker 
309*61046927SAndroid Build Coastguard Worker       b->func_param_idx = 0;
310*61046927SAndroid Build Coastguard Worker 
311*61046927SAndroid Build Coastguard Worker       /* The return value is the first parameter */
312*61046927SAndroid Build Coastguard Worker       if (func_type->return_type->base_type != vtn_base_type_void)
313*61046927SAndroid Build Coastguard Worker          b->func_param_idx++;
314*61046927SAndroid Build Coastguard Worker       break;
315*61046927SAndroid Build Coastguard Worker    }
316*61046927SAndroid Build Coastguard Worker 
317*61046927SAndroid Build Coastguard Worker    case SpvOpFunctionEnd:
318*61046927SAndroid Build Coastguard Worker       b->func->end = w;
319*61046927SAndroid Build Coastguard Worker       if (b->func->start_block == NULL) {
320*61046927SAndroid Build Coastguard Worker          vtn_fail_if(b->func->linkage != SpvLinkageTypeImport,
321*61046927SAndroid Build Coastguard Worker                      "A function declaration (an OpFunction with no basic "
322*61046927SAndroid Build Coastguard Worker                      "blocks), must have a Linkage Attributes Decoration "
323*61046927SAndroid Build Coastguard Worker                      "with the Import Linkage Type.");
324*61046927SAndroid Build Coastguard Worker 
325*61046927SAndroid Build Coastguard Worker          /* In this case, the function didn't have any actual blocks.  It's
326*61046927SAndroid Build Coastguard Worker           * just a prototype so delete the function_impl.
327*61046927SAndroid Build Coastguard Worker           */
328*61046927SAndroid Build Coastguard Worker          b->func->nir_func->impl = NULL;
329*61046927SAndroid Build Coastguard Worker       } else {
330*61046927SAndroid Build Coastguard Worker          vtn_fail_if(b->func->linkage == SpvLinkageTypeImport,
331*61046927SAndroid Build Coastguard Worker                      "A function definition (an OpFunction with basic blocks) "
332*61046927SAndroid Build Coastguard Worker                      "cannot be decorated with the Import Linkage Type.");
333*61046927SAndroid Build Coastguard Worker       }
334*61046927SAndroid Build Coastguard Worker       b->func = NULL;
335*61046927SAndroid Build Coastguard Worker       break;
336*61046927SAndroid Build Coastguard Worker 
337*61046927SAndroid Build Coastguard Worker    case SpvOpFunctionParameter: {
338*61046927SAndroid Build Coastguard Worker       vtn_assert(b->func_param_idx < b->func->nir_func->num_params);
339*61046927SAndroid Build Coastguard Worker 
340*61046927SAndroid Build Coastguard Worker       struct vtn_func_arg_info arg_info = {0};
341*61046927SAndroid Build Coastguard Worker       struct vtn_type *type = vtn_get_type(b, w[1]);
342*61046927SAndroid Build Coastguard Worker       struct vtn_ssa_value *ssa = vtn_create_ssa_value(b, type->type);
343*61046927SAndroid Build Coastguard Worker       struct vtn_value *val = vtn_untyped_value(b, w[2]);
344*61046927SAndroid Build Coastguard Worker 
345*61046927SAndroid Build Coastguard Worker       vtn_foreach_decoration(b, val, function_parameter_decoration_cb, &arg_info);
346*61046927SAndroid Build Coastguard Worker       vtn_ssa_value_load_function_param(b, ssa, type, &arg_info, &b->func_param_idx);
347*61046927SAndroid Build Coastguard Worker       vtn_push_ssa_value(b, w[2], ssa);
348*61046927SAndroid Build Coastguard Worker       break;
349*61046927SAndroid Build Coastguard Worker    }
350*61046927SAndroid Build Coastguard Worker 
351*61046927SAndroid Build Coastguard Worker    case SpvOpLabel: {
352*61046927SAndroid Build Coastguard Worker       vtn_assert(b->block == NULL);
353*61046927SAndroid Build Coastguard Worker       b->block = vtn_zalloc(b, struct vtn_block);
354*61046927SAndroid Build Coastguard Worker       b->block->label = w;
355*61046927SAndroid Build Coastguard Worker       vtn_push_value(b, w[1], vtn_value_type_block)->block = b->block;
356*61046927SAndroid Build Coastguard Worker 
357*61046927SAndroid Build Coastguard Worker       b->func->block_count++;
358*61046927SAndroid Build Coastguard Worker 
359*61046927SAndroid Build Coastguard Worker       if (b->func->start_block == NULL) {
360*61046927SAndroid Build Coastguard Worker          /* This is the first block encountered for this function.  In this
361*61046927SAndroid Build Coastguard Worker           * case, we set the start block and add it to the list of
362*61046927SAndroid Build Coastguard Worker           * implemented functions that we'll walk later.
363*61046927SAndroid Build Coastguard Worker           */
364*61046927SAndroid Build Coastguard Worker          b->func->start_block = b->block;
365*61046927SAndroid Build Coastguard Worker          list_addtail(&b->func->link, &b->functions);
366*61046927SAndroid Build Coastguard Worker       }
367*61046927SAndroid Build Coastguard Worker       break;
368*61046927SAndroid Build Coastguard Worker    }
369*61046927SAndroid Build Coastguard Worker 
370*61046927SAndroid Build Coastguard Worker    case SpvOpSelectionMerge:
371*61046927SAndroid Build Coastguard Worker    case SpvOpLoopMerge:
372*61046927SAndroid Build Coastguard Worker       vtn_assert(b->block && b->block->merge == NULL);
373*61046927SAndroid Build Coastguard Worker       b->block->merge = w;
374*61046927SAndroid Build Coastguard Worker       break;
375*61046927SAndroid Build Coastguard Worker 
376*61046927SAndroid Build Coastguard Worker    case SpvOpBranch:
377*61046927SAndroid Build Coastguard Worker    case SpvOpBranchConditional:
378*61046927SAndroid Build Coastguard Worker    case SpvOpSwitch:
379*61046927SAndroid Build Coastguard Worker    case SpvOpKill:
380*61046927SAndroid Build Coastguard Worker    case SpvOpTerminateInvocation:
381*61046927SAndroid Build Coastguard Worker    case SpvOpIgnoreIntersectionKHR:
382*61046927SAndroid Build Coastguard Worker    case SpvOpTerminateRayKHR:
383*61046927SAndroid Build Coastguard Worker    case SpvOpEmitMeshTasksEXT:
384*61046927SAndroid Build Coastguard Worker    case SpvOpReturn:
385*61046927SAndroid Build Coastguard Worker    case SpvOpReturnValue:
386*61046927SAndroid Build Coastguard Worker    case SpvOpUnreachable:
387*61046927SAndroid Build Coastguard Worker       if (b->wa_ignore_return_after_emit_mesh_tasks &&
388*61046927SAndroid Build Coastguard Worker           opcode == SpvOpReturn && !b->block) {
389*61046927SAndroid Build Coastguard Worker             /* At this point block was already reset by
390*61046927SAndroid Build Coastguard Worker              * SpvOpEmitMeshTasksEXT. */
391*61046927SAndroid Build Coastguard Worker             break;
392*61046927SAndroid Build Coastguard Worker       }
393*61046927SAndroid Build Coastguard Worker       vtn_assert(b->block && b->block->branch == NULL);
394*61046927SAndroid Build Coastguard Worker       b->block->branch = w;
395*61046927SAndroid Build Coastguard Worker       b->block = NULL;
396*61046927SAndroid Build Coastguard Worker       break;
397*61046927SAndroid Build Coastguard Worker 
398*61046927SAndroid Build Coastguard Worker    default:
399*61046927SAndroid Build Coastguard Worker       /* Continue on as per normal */
400*61046927SAndroid Build Coastguard Worker       return true;
401*61046927SAndroid Build Coastguard Worker    }
402*61046927SAndroid Build Coastguard Worker 
403*61046927SAndroid Build Coastguard Worker    return true;
404*61046927SAndroid Build Coastguard Worker }
405*61046927SAndroid Build Coastguard Worker 
406*61046927SAndroid Build Coastguard Worker /* returns the default block */
407*61046927SAndroid Build Coastguard Worker void
vtn_parse_switch(struct vtn_builder * b,const uint32_t * branch,struct list_head * case_list)408*61046927SAndroid Build Coastguard Worker vtn_parse_switch(struct vtn_builder *b,
409*61046927SAndroid Build Coastguard Worker                  const uint32_t *branch,
410*61046927SAndroid Build Coastguard Worker                  struct list_head *case_list)
411*61046927SAndroid Build Coastguard Worker {
412*61046927SAndroid Build Coastguard Worker    const uint32_t *branch_end = branch + (branch[0] >> SpvWordCountShift);
413*61046927SAndroid Build Coastguard Worker 
414*61046927SAndroid Build Coastguard Worker    struct vtn_value *sel_val = vtn_untyped_value(b, branch[1]);
415*61046927SAndroid Build Coastguard Worker    vtn_fail_if(!sel_val->type ||
416*61046927SAndroid Build Coastguard Worker                sel_val->type->base_type != vtn_base_type_scalar,
417*61046927SAndroid Build Coastguard Worker                "Selector of OpSwitch must have a type of OpTypeInt");
418*61046927SAndroid Build Coastguard Worker 
419*61046927SAndroid Build Coastguard Worker    nir_alu_type sel_type =
420*61046927SAndroid Build Coastguard Worker       nir_get_nir_type_for_glsl_type(sel_val->type->type);
421*61046927SAndroid Build Coastguard Worker    vtn_fail_if(nir_alu_type_get_base_type(sel_type) != nir_type_int &&
422*61046927SAndroid Build Coastguard Worker                nir_alu_type_get_base_type(sel_type) != nir_type_uint,
423*61046927SAndroid Build Coastguard Worker                "Selector of OpSwitch must have a type of OpTypeInt");
424*61046927SAndroid Build Coastguard Worker 
425*61046927SAndroid Build Coastguard Worker    struct hash_table *block_to_case = _mesa_pointer_hash_table_create(b);
426*61046927SAndroid Build Coastguard Worker 
427*61046927SAndroid Build Coastguard Worker    bool is_default = true;
428*61046927SAndroid Build Coastguard Worker    const unsigned bitsize = nir_alu_type_get_type_size(sel_type);
429*61046927SAndroid Build Coastguard Worker    for (const uint32_t *w = branch + 2; w < branch_end;) {
430*61046927SAndroid Build Coastguard Worker       uint64_t literal = 0;
431*61046927SAndroid Build Coastguard Worker       if (!is_default) {
432*61046927SAndroid Build Coastguard Worker          if (bitsize <= 32) {
433*61046927SAndroid Build Coastguard Worker             literal = *(w++);
434*61046927SAndroid Build Coastguard Worker          } else {
435*61046927SAndroid Build Coastguard Worker             assert(bitsize == 64);
436*61046927SAndroid Build Coastguard Worker             literal = vtn_u64_literal(w);
437*61046927SAndroid Build Coastguard Worker             w += 2;
438*61046927SAndroid Build Coastguard Worker          }
439*61046927SAndroid Build Coastguard Worker       }
440*61046927SAndroid Build Coastguard Worker       struct vtn_block *case_block = vtn_block(b, *(w++));
441*61046927SAndroid Build Coastguard Worker 
442*61046927SAndroid Build Coastguard Worker       struct hash_entry *case_entry =
443*61046927SAndroid Build Coastguard Worker          _mesa_hash_table_search(block_to_case, case_block);
444*61046927SAndroid Build Coastguard Worker 
445*61046927SAndroid Build Coastguard Worker       struct vtn_case *cse;
446*61046927SAndroid Build Coastguard Worker       if (case_entry) {
447*61046927SAndroid Build Coastguard Worker          cse = case_entry->data;
448*61046927SAndroid Build Coastguard Worker       } else {
449*61046927SAndroid Build Coastguard Worker          cse = vtn_zalloc(b, struct vtn_case);
450*61046927SAndroid Build Coastguard Worker          cse->block = case_block;
451*61046927SAndroid Build Coastguard Worker          cse->block->switch_case = cse;
452*61046927SAndroid Build Coastguard Worker          util_dynarray_init(&cse->values, b);
453*61046927SAndroid Build Coastguard Worker 
454*61046927SAndroid Build Coastguard Worker          list_addtail(&cse->link, case_list);
455*61046927SAndroid Build Coastguard Worker          _mesa_hash_table_insert(block_to_case, case_block, cse);
456*61046927SAndroid Build Coastguard Worker       }
457*61046927SAndroid Build Coastguard Worker 
458*61046927SAndroid Build Coastguard Worker       if (is_default) {
459*61046927SAndroid Build Coastguard Worker          cse->is_default = true;
460*61046927SAndroid Build Coastguard Worker       } else {
461*61046927SAndroid Build Coastguard Worker          util_dynarray_append(&cse->values, uint64_t, literal);
462*61046927SAndroid Build Coastguard Worker       }
463*61046927SAndroid Build Coastguard Worker 
464*61046927SAndroid Build Coastguard Worker       is_default = false;
465*61046927SAndroid Build Coastguard Worker    }
466*61046927SAndroid Build Coastguard Worker 
467*61046927SAndroid Build Coastguard Worker    _mesa_hash_table_destroy(block_to_case, NULL);
468*61046927SAndroid Build Coastguard Worker }
469*61046927SAndroid Build Coastguard Worker 
470*61046927SAndroid Build Coastguard Worker void
vtn_build_cfg(struct vtn_builder * b,const uint32_t * words,const uint32_t * end)471*61046927SAndroid Build Coastguard Worker vtn_build_cfg(struct vtn_builder *b, const uint32_t *words, const uint32_t *end)
472*61046927SAndroid Build Coastguard Worker {
473*61046927SAndroid Build Coastguard Worker    vtn_foreach_instruction(b, words, end,
474*61046927SAndroid Build Coastguard Worker                            vtn_cfg_handle_prepass_instruction);
475*61046927SAndroid Build Coastguard Worker 
476*61046927SAndroid Build Coastguard Worker    if (b->shader->info.stage == MESA_SHADER_KERNEL)
477*61046927SAndroid Build Coastguard Worker       return;
478*61046927SAndroid Build Coastguard Worker 
479*61046927SAndroid Build Coastguard Worker    vtn_build_structured_cfg(b, words, end);
480*61046927SAndroid Build Coastguard Worker }
481*61046927SAndroid Build Coastguard Worker 
482*61046927SAndroid Build Coastguard Worker bool
vtn_handle_phis_first_pass(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)483*61046927SAndroid Build Coastguard Worker vtn_handle_phis_first_pass(struct vtn_builder *b, SpvOp opcode,
484*61046927SAndroid Build Coastguard Worker                            const uint32_t *w, unsigned count)
485*61046927SAndroid Build Coastguard Worker {
486*61046927SAndroid Build Coastguard Worker    if (opcode == SpvOpLabel)
487*61046927SAndroid Build Coastguard Worker       return true; /* Nothing to do */
488*61046927SAndroid Build Coastguard Worker 
489*61046927SAndroid Build Coastguard Worker    /* If this isn't a phi node, stop. */
490*61046927SAndroid Build Coastguard Worker    if (opcode != SpvOpPhi)
491*61046927SAndroid Build Coastguard Worker       return false;
492*61046927SAndroid Build Coastguard Worker 
493*61046927SAndroid Build Coastguard Worker    /* For handling phi nodes, we do a poor-man's out-of-ssa on the spot.
494*61046927SAndroid Build Coastguard Worker     * For each phi, we create a variable with the appropreate type and
495*61046927SAndroid Build Coastguard Worker     * do a load from that variable.  Then, in a second pass, we add
496*61046927SAndroid Build Coastguard Worker     * stores to that variable to each of the predecessor blocks.
497*61046927SAndroid Build Coastguard Worker     *
498*61046927SAndroid Build Coastguard Worker     * We could do something more intelligent here.  However, in order to
499*61046927SAndroid Build Coastguard Worker     * handle loops and things properly, we really need dominance
500*61046927SAndroid Build Coastguard Worker     * information.  It would end up basically being the into-SSA
501*61046927SAndroid Build Coastguard Worker     * algorithm all over again.  It's easier if we just let
502*61046927SAndroid Build Coastguard Worker     * lower_vars_to_ssa do that for us instead of repeating it here.
503*61046927SAndroid Build Coastguard Worker     */
504*61046927SAndroid Build Coastguard Worker    struct vtn_type *type = vtn_get_type(b, w[1]);
505*61046927SAndroid Build Coastguard Worker    nir_variable *phi_var =
506*61046927SAndroid Build Coastguard Worker       nir_local_variable_create(b->nb.impl, type->type, "phi");
507*61046927SAndroid Build Coastguard Worker 
508*61046927SAndroid Build Coastguard Worker    struct vtn_value *phi_val = vtn_untyped_value(b, w[2]);
509*61046927SAndroid Build Coastguard Worker    if (vtn_value_is_relaxed_precision(b, phi_val))
510*61046927SAndroid Build Coastguard Worker       phi_var->data.precision = GLSL_PRECISION_MEDIUM;
511*61046927SAndroid Build Coastguard Worker 
512*61046927SAndroid Build Coastguard Worker    _mesa_hash_table_insert(b->phi_table, w, phi_var);
513*61046927SAndroid Build Coastguard Worker 
514*61046927SAndroid Build Coastguard Worker    vtn_push_ssa_value(b, w[2],
515*61046927SAndroid Build Coastguard Worker       vtn_local_load(b, nir_build_deref_var(&b->nb, phi_var), 0));
516*61046927SAndroid Build Coastguard Worker 
517*61046927SAndroid Build Coastguard Worker    return true;
518*61046927SAndroid Build Coastguard Worker }
519*61046927SAndroid Build Coastguard Worker 
520*61046927SAndroid Build Coastguard Worker static bool
vtn_handle_phi_second_pass(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)521*61046927SAndroid Build Coastguard Worker vtn_handle_phi_second_pass(struct vtn_builder *b, SpvOp opcode,
522*61046927SAndroid Build Coastguard Worker                            const uint32_t *w, unsigned count)
523*61046927SAndroid Build Coastguard Worker {
524*61046927SAndroid Build Coastguard Worker    if (opcode != SpvOpPhi)
525*61046927SAndroid Build Coastguard Worker       return true;
526*61046927SAndroid Build Coastguard Worker 
527*61046927SAndroid Build Coastguard Worker    struct hash_entry *phi_entry = _mesa_hash_table_search(b->phi_table, w);
528*61046927SAndroid Build Coastguard Worker 
529*61046927SAndroid Build Coastguard Worker    /* It's possible that this phi is in an unreachable block in which case it
530*61046927SAndroid Build Coastguard Worker     * may never have been emitted and therefore may not be in the hash table.
531*61046927SAndroid Build Coastguard Worker     * In this case, there's no var for it and it's safe to just bail.
532*61046927SAndroid Build Coastguard Worker     */
533*61046927SAndroid Build Coastguard Worker    if (phi_entry == NULL)
534*61046927SAndroid Build Coastguard Worker       return true;
535*61046927SAndroid Build Coastguard Worker 
536*61046927SAndroid Build Coastguard Worker    nir_variable *phi_var = phi_entry->data;
537*61046927SAndroid Build Coastguard Worker 
538*61046927SAndroid Build Coastguard Worker    for (unsigned i = 3; i < count; i += 2) {
539*61046927SAndroid Build Coastguard Worker       struct vtn_block *pred = vtn_block(b, w[i + 1]);
540*61046927SAndroid Build Coastguard Worker 
541*61046927SAndroid Build Coastguard Worker       /* If block does not have end_nop, that is because it is an unreacheable
542*61046927SAndroid Build Coastguard Worker        * block, and hence it is not worth to handle it */
543*61046927SAndroid Build Coastguard Worker       if (!pred->end_nop)
544*61046927SAndroid Build Coastguard Worker          continue;
545*61046927SAndroid Build Coastguard Worker 
546*61046927SAndroid Build Coastguard Worker       b->nb.cursor = nir_after_instr(&pred->end_nop->instr);
547*61046927SAndroid Build Coastguard Worker 
548*61046927SAndroid Build Coastguard Worker       struct vtn_ssa_value *src = vtn_ssa_value(b, w[i]);
549*61046927SAndroid Build Coastguard Worker 
550*61046927SAndroid Build Coastguard Worker       vtn_local_store(b, src, nir_build_deref_var(&b->nb, phi_var), 0);
551*61046927SAndroid Build Coastguard Worker    }
552*61046927SAndroid Build Coastguard Worker 
553*61046927SAndroid Build Coastguard Worker    return true;
554*61046927SAndroid Build Coastguard Worker }
555*61046927SAndroid Build Coastguard Worker 
556*61046927SAndroid Build Coastguard Worker void
vtn_emit_ret_store(struct vtn_builder * b,const struct vtn_block * block)557*61046927SAndroid Build Coastguard Worker vtn_emit_ret_store(struct vtn_builder *b, const struct vtn_block *block)
558*61046927SAndroid Build Coastguard Worker {
559*61046927SAndroid Build Coastguard Worker    if ((*block->branch & SpvOpCodeMask) != SpvOpReturnValue)
560*61046927SAndroid Build Coastguard Worker       return;
561*61046927SAndroid Build Coastguard Worker 
562*61046927SAndroid Build Coastguard Worker    vtn_fail_if(b->func->type->return_type->base_type == vtn_base_type_void,
563*61046927SAndroid Build Coastguard Worker                "Return with a value from a function returning void");
564*61046927SAndroid Build Coastguard Worker    struct vtn_ssa_value *src = vtn_ssa_value(b, block->branch[1]);
565*61046927SAndroid Build Coastguard Worker    const struct glsl_type *ret_type =
566*61046927SAndroid Build Coastguard Worker       glsl_get_bare_type(b->func->type->return_type->type);
567*61046927SAndroid Build Coastguard Worker    nir_deref_instr *ret_deref =
568*61046927SAndroid Build Coastguard Worker       nir_build_deref_cast(&b->nb, nir_load_param(&b->nb, 0),
569*61046927SAndroid Build Coastguard Worker                            nir_var_function_temp, ret_type, 0);
570*61046927SAndroid Build Coastguard Worker    vtn_local_store(b, src, ret_deref, 0);
571*61046927SAndroid Build Coastguard Worker }
572*61046927SAndroid Build Coastguard Worker 
573*61046927SAndroid Build Coastguard Worker static struct nir_block *
vtn_new_unstructured_block(struct vtn_builder * b,struct vtn_function * func)574*61046927SAndroid Build Coastguard Worker vtn_new_unstructured_block(struct vtn_builder *b, struct vtn_function *func)
575*61046927SAndroid Build Coastguard Worker {
576*61046927SAndroid Build Coastguard Worker    struct nir_block *n = nir_block_create(b->shader);
577*61046927SAndroid Build Coastguard Worker    exec_list_push_tail(&func->nir_func->impl->body, &n->cf_node.node);
578*61046927SAndroid Build Coastguard Worker    n->cf_node.parent = &func->nir_func->impl->cf_node;
579*61046927SAndroid Build Coastguard Worker    return n;
580*61046927SAndroid Build Coastguard Worker }
581*61046927SAndroid Build Coastguard Worker 
582*61046927SAndroid Build Coastguard Worker static void
vtn_add_unstructured_block(struct vtn_builder * b,struct vtn_function * func,struct list_head * work_list,struct vtn_block * block)583*61046927SAndroid Build Coastguard Worker vtn_add_unstructured_block(struct vtn_builder *b,
584*61046927SAndroid Build Coastguard Worker                            struct vtn_function *func,
585*61046927SAndroid Build Coastguard Worker                            struct list_head *work_list,
586*61046927SAndroid Build Coastguard Worker                            struct vtn_block *block)
587*61046927SAndroid Build Coastguard Worker {
588*61046927SAndroid Build Coastguard Worker    if (!block->block) {
589*61046927SAndroid Build Coastguard Worker       block->block = vtn_new_unstructured_block(b, func);
590*61046927SAndroid Build Coastguard Worker       list_addtail(&block->link, work_list);
591*61046927SAndroid Build Coastguard Worker    }
592*61046927SAndroid Build Coastguard Worker }
593*61046927SAndroid Build Coastguard Worker 
594*61046927SAndroid Build Coastguard Worker static void
vtn_emit_cf_func_unstructured(struct vtn_builder * b,struct vtn_function * func,vtn_instruction_handler handler)595*61046927SAndroid Build Coastguard Worker vtn_emit_cf_func_unstructured(struct vtn_builder *b, struct vtn_function *func,
596*61046927SAndroid Build Coastguard Worker                               vtn_instruction_handler handler)
597*61046927SAndroid Build Coastguard Worker {
598*61046927SAndroid Build Coastguard Worker    struct list_head work_list;
599*61046927SAndroid Build Coastguard Worker    list_inithead(&work_list);
600*61046927SAndroid Build Coastguard Worker 
601*61046927SAndroid Build Coastguard Worker    func->start_block->block = nir_start_block(func->nir_func->impl);
602*61046927SAndroid Build Coastguard Worker    list_addtail(&func->start_block->link, &work_list);
603*61046927SAndroid Build Coastguard Worker    while (!list_is_empty(&work_list)) {
604*61046927SAndroid Build Coastguard Worker       struct vtn_block *block =
605*61046927SAndroid Build Coastguard Worker          list_first_entry(&work_list, struct vtn_block, link);
606*61046927SAndroid Build Coastguard Worker       list_del(&block->link);
607*61046927SAndroid Build Coastguard Worker 
608*61046927SAndroid Build Coastguard Worker       vtn_assert(block->block);
609*61046927SAndroid Build Coastguard Worker 
610*61046927SAndroid Build Coastguard Worker       const uint32_t *block_start = block->label;
611*61046927SAndroid Build Coastguard Worker       const uint32_t *block_end = block->branch;
612*61046927SAndroid Build Coastguard Worker 
613*61046927SAndroid Build Coastguard Worker       b->nb.cursor = nir_after_block(block->block);
614*61046927SAndroid Build Coastguard Worker       block_start = vtn_foreach_instruction(b, block_start, block_end,
615*61046927SAndroid Build Coastguard Worker                                             vtn_handle_phis_first_pass);
616*61046927SAndroid Build Coastguard Worker       vtn_foreach_instruction(b, block_start, block_end, handler);
617*61046927SAndroid Build Coastguard Worker       block->end_nop = nir_nop(&b->nb);
618*61046927SAndroid Build Coastguard Worker 
619*61046927SAndroid Build Coastguard Worker       SpvOp op = *block_end & SpvOpCodeMask;
620*61046927SAndroid Build Coastguard Worker       switch (op) {
621*61046927SAndroid Build Coastguard Worker       case SpvOpBranch: {
622*61046927SAndroid Build Coastguard Worker          struct vtn_block *branch_block = vtn_block(b, block->branch[1]);
623*61046927SAndroid Build Coastguard Worker          vtn_add_unstructured_block(b, func, &work_list, branch_block);
624*61046927SAndroid Build Coastguard Worker          nir_goto(&b->nb, branch_block->block);
625*61046927SAndroid Build Coastguard Worker          break;
626*61046927SAndroid Build Coastguard Worker       }
627*61046927SAndroid Build Coastguard Worker 
628*61046927SAndroid Build Coastguard Worker       case SpvOpBranchConditional: {
629*61046927SAndroid Build Coastguard Worker          nir_def *cond = vtn_ssa_value(b, block->branch[1])->def;
630*61046927SAndroid Build Coastguard Worker          struct vtn_block *then_block = vtn_block(b, block->branch[2]);
631*61046927SAndroid Build Coastguard Worker          struct vtn_block *else_block = vtn_block(b, block->branch[3]);
632*61046927SAndroid Build Coastguard Worker 
633*61046927SAndroid Build Coastguard Worker          vtn_add_unstructured_block(b, func, &work_list, then_block);
634*61046927SAndroid Build Coastguard Worker          if (then_block == else_block) {
635*61046927SAndroid Build Coastguard Worker             nir_goto(&b->nb, then_block->block);
636*61046927SAndroid Build Coastguard Worker          } else {
637*61046927SAndroid Build Coastguard Worker             vtn_add_unstructured_block(b, func, &work_list, else_block);
638*61046927SAndroid Build Coastguard Worker             nir_goto_if(&b->nb, then_block->block, cond, else_block->block);
639*61046927SAndroid Build Coastguard Worker          }
640*61046927SAndroid Build Coastguard Worker 
641*61046927SAndroid Build Coastguard Worker          break;
642*61046927SAndroid Build Coastguard Worker       }
643*61046927SAndroid Build Coastguard Worker 
644*61046927SAndroid Build Coastguard Worker       case SpvOpSwitch: {
645*61046927SAndroid Build Coastguard Worker          struct list_head cases;
646*61046927SAndroid Build Coastguard Worker          list_inithead(&cases);
647*61046927SAndroid Build Coastguard Worker          vtn_parse_switch(b, block->branch, &cases);
648*61046927SAndroid Build Coastguard Worker 
649*61046927SAndroid Build Coastguard Worker          nir_def *sel = vtn_get_nir_ssa(b, block->branch[1]);
650*61046927SAndroid Build Coastguard Worker 
651*61046927SAndroid Build Coastguard Worker          struct vtn_case *def = NULL;
652*61046927SAndroid Build Coastguard Worker          vtn_foreach_case(cse, &cases) {
653*61046927SAndroid Build Coastguard Worker             if (cse->is_default) {
654*61046927SAndroid Build Coastguard Worker                assert(def == NULL);
655*61046927SAndroid Build Coastguard Worker                def = cse;
656*61046927SAndroid Build Coastguard Worker                continue;
657*61046927SAndroid Build Coastguard Worker             }
658*61046927SAndroid Build Coastguard Worker 
659*61046927SAndroid Build Coastguard Worker             nir_def *cond = nir_imm_false(&b->nb);
660*61046927SAndroid Build Coastguard Worker             util_dynarray_foreach(&cse->values, uint64_t, val)
661*61046927SAndroid Build Coastguard Worker                cond = nir_ior(&b->nb, cond, nir_ieq_imm(&b->nb, sel, *val));
662*61046927SAndroid Build Coastguard Worker 
663*61046927SAndroid Build Coastguard Worker             /* block for the next check */
664*61046927SAndroid Build Coastguard Worker             nir_block *e = vtn_new_unstructured_block(b, func);
665*61046927SAndroid Build Coastguard Worker             vtn_add_unstructured_block(b, func, &work_list, cse->block);
666*61046927SAndroid Build Coastguard Worker 
667*61046927SAndroid Build Coastguard Worker             /* add branching */
668*61046927SAndroid Build Coastguard Worker             nir_goto_if(&b->nb, cse->block->block, cond, e);
669*61046927SAndroid Build Coastguard Worker             b->nb.cursor = nir_after_block(e);
670*61046927SAndroid Build Coastguard Worker          }
671*61046927SAndroid Build Coastguard Worker 
672*61046927SAndroid Build Coastguard Worker          vtn_assert(def != NULL);
673*61046927SAndroid Build Coastguard Worker          vtn_add_unstructured_block(b, func, &work_list, def->block);
674*61046927SAndroid Build Coastguard Worker 
675*61046927SAndroid Build Coastguard Worker          /* now that all cases are handled, branch into the default block */
676*61046927SAndroid Build Coastguard Worker          nir_goto(&b->nb, def->block->block);
677*61046927SAndroid Build Coastguard Worker          break;
678*61046927SAndroid Build Coastguard Worker       }
679*61046927SAndroid Build Coastguard Worker 
680*61046927SAndroid Build Coastguard Worker       case SpvOpKill: {
681*61046927SAndroid Build Coastguard Worker          nir_discard(&b->nb);
682*61046927SAndroid Build Coastguard Worker          nir_goto(&b->nb, b->func->nir_func->impl->end_block);
683*61046927SAndroid Build Coastguard Worker          break;
684*61046927SAndroid Build Coastguard Worker       }
685*61046927SAndroid Build Coastguard Worker 
686*61046927SAndroid Build Coastguard Worker       case SpvOpUnreachable:
687*61046927SAndroid Build Coastguard Worker       case SpvOpReturn:
688*61046927SAndroid Build Coastguard Worker       case SpvOpReturnValue: {
689*61046927SAndroid Build Coastguard Worker          vtn_emit_ret_store(b, block);
690*61046927SAndroid Build Coastguard Worker          nir_goto(&b->nb, b->func->nir_func->impl->end_block);
691*61046927SAndroid Build Coastguard Worker          break;
692*61046927SAndroid Build Coastguard Worker       }
693*61046927SAndroid Build Coastguard Worker 
694*61046927SAndroid Build Coastguard Worker       default:
695*61046927SAndroid Build Coastguard Worker          vtn_fail("Unhandled opcode %s", spirv_op_to_string(op));
696*61046927SAndroid Build Coastguard Worker       }
697*61046927SAndroid Build Coastguard Worker    }
698*61046927SAndroid Build Coastguard Worker }
699*61046927SAndroid Build Coastguard Worker 
700*61046927SAndroid Build Coastguard Worker void
vtn_function_emit(struct vtn_builder * b,struct vtn_function * func,vtn_instruction_handler instruction_handler)701*61046927SAndroid Build Coastguard Worker vtn_function_emit(struct vtn_builder *b, struct vtn_function *func,
702*61046927SAndroid Build Coastguard Worker                   vtn_instruction_handler instruction_handler)
703*61046927SAndroid Build Coastguard Worker {
704*61046927SAndroid Build Coastguard Worker    static int force_unstructured = -1;
705*61046927SAndroid Build Coastguard Worker    if (force_unstructured < 0) {
706*61046927SAndroid Build Coastguard Worker       force_unstructured =
707*61046927SAndroid Build Coastguard Worker          debug_get_bool_option("MESA_SPIRV_FORCE_UNSTRUCTURED", false);
708*61046927SAndroid Build Coastguard Worker    }
709*61046927SAndroid Build Coastguard Worker 
710*61046927SAndroid Build Coastguard Worker    nir_function_impl *impl = func->nir_func->impl;
711*61046927SAndroid Build Coastguard Worker    b->nb = nir_builder_at(nir_after_impl(impl));
712*61046927SAndroid Build Coastguard Worker    b->func = func;
713*61046927SAndroid Build Coastguard Worker    b->nb.exact = b->exact;
714*61046927SAndroid Build Coastguard Worker    b->phi_table = _mesa_pointer_hash_table_create(b);
715*61046927SAndroid Build Coastguard Worker 
716*61046927SAndroid Build Coastguard Worker    if (b->shader->info.stage == MESA_SHADER_KERNEL || force_unstructured) {
717*61046927SAndroid Build Coastguard Worker       impl->structured = false;
718*61046927SAndroid Build Coastguard Worker       vtn_emit_cf_func_unstructured(b, func, instruction_handler);
719*61046927SAndroid Build Coastguard Worker    } else {
720*61046927SAndroid Build Coastguard Worker       vtn_emit_cf_func_structured(b, func, instruction_handler);
721*61046927SAndroid Build Coastguard Worker    }
722*61046927SAndroid Build Coastguard Worker 
723*61046927SAndroid Build Coastguard Worker    vtn_foreach_instruction(b, func->start_block->label, func->end,
724*61046927SAndroid Build Coastguard Worker                            vtn_handle_phi_second_pass);
725*61046927SAndroid Build Coastguard Worker 
726*61046927SAndroid Build Coastguard Worker    if (func->nir_func->impl->structured)
727*61046927SAndroid Build Coastguard Worker       nir_copy_prop_impl(impl);
728*61046927SAndroid Build Coastguard Worker    nir_rematerialize_derefs_in_use_blocks_impl(impl);
729*61046927SAndroid Build Coastguard Worker 
730*61046927SAndroid Build Coastguard Worker    /*
731*61046927SAndroid Build Coastguard Worker     * There are some cases where we need to repair SSA to insert
732*61046927SAndroid Build Coastguard Worker     * the needed phi nodes:
733*61046927SAndroid Build Coastguard Worker     *
734*61046927SAndroid Build Coastguard Worker     * - Early termination instructions `OpKill` and `OpTerminateInvocation`,
735*61046927SAndroid Build Coastguard Worker     *   in NIR. They're represented by regular intrinsics with no control-flow
736*61046927SAndroid Build Coastguard Worker     *   semantics. This means that the SSA form from the SPIR-V may not
737*61046927SAndroid Build Coastguard Worker     *   100% match NIR.
738*61046927SAndroid Build Coastguard Worker     *
739*61046927SAndroid Build Coastguard Worker     * - Switches with only default case may also define SSA which may
740*61046927SAndroid Build Coastguard Worker     *   subsequently be used out of the switch.
741*61046927SAndroid Build Coastguard Worker     */
742*61046927SAndroid Build Coastguard Worker    if (func->nir_func->impl->structured)
743*61046927SAndroid Build Coastguard Worker       nir_repair_ssa_impl(impl);
744*61046927SAndroid Build Coastguard Worker 
745*61046927SAndroid Build Coastguard Worker    func->emitted = true;
746*61046927SAndroid Build Coastguard Worker }
747