• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2024 Valve Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "gl_nir_linker.h"
25 #include "linker_util.h"
26 #include "program/symbol_table.h"
27 #include "util/hash_table.h"
28 #include "main/shader_types.h"
29 
30 struct function_sig {
31    nir_function *func;
32 
33    struct list_head node;
34 };
35 
36 typedef enum {
37    PARAMETER_LIST_NO_MATCH,
38    PARAMETER_LIST_EXACT_MATCH,
39    PARAMETER_LIST_INEXACT_MATCH /* Match requires implicit conversion. */
40 } parameter_list_match_t;
41 
42 /**
43  * Check if two parameter lists match.
44  *
45  * list_a Parameters of the function definition.
46  * list_b Actual parameters passed to the function.
47  */
48 static parameter_list_match_t
parameter_lists_match(bool has_implicit_conversions,bool has_implicit_int_to_uint_conversion,nir_parameter * list_a,unsigned num_params_a,nir_parameter * list_b,unsigned num_params_b)49 parameter_lists_match(bool has_implicit_conversions,
50                       bool has_implicit_int_to_uint_conversion,
51                       nir_parameter *list_a, unsigned num_params_a,
52                       nir_parameter *list_b, unsigned num_params_b)
53 {
54    /* The lists have different length and by definition do not match. */
55    if (num_params_a != num_params_b)
56       return PARAMETER_LIST_NO_MATCH;
57 
58    nir_parameter *param_a;
59    nir_parameter *param_b;
60 
61    /* This is set to true if there is an inexact match requiring an implicit
62     * conversion. */
63    bool inexact_match = false;
64 
65    for (int i = 0; i < num_params_a; i++) {
66       param_a = &list_a[i];
67       param_b = &list_b[i];
68 
69       if (param_a->type == param_b->type)
70          continue;
71 
72       /* Try to find an implicit conversion from actual to param. */
73       inexact_match = true;
74 
75       switch (param_a->mode) {
76       case nir_var_function_in:
77          if (param_a->implicit_conversion_prohibited ||
78              !_mesa_glsl_can_implicitly_convert(param_b->type, param_a->type,
79                                                 has_implicit_conversions,
80                                                 has_implicit_int_to_uint_conversion))
81             return PARAMETER_LIST_NO_MATCH;
82          break;
83 
84       case nir_var_function_out:
85          if (!_mesa_glsl_can_implicitly_convert(param_a->type, param_b->type,
86                                                 has_implicit_conversions,
87                                                 has_implicit_int_to_uint_conversion))
88             return PARAMETER_LIST_NO_MATCH;
89          break;
90 
91       case nir_var_function_inout:
92          /* Since there are no bi-directional automatic conversions (e.g.,
93           * there is int -> float but no float -> int), inout parameters must
94           * be exact matches.
95           */
96          return PARAMETER_LIST_NO_MATCH;
97 
98       default:
99          assert(false);
100          return PARAMETER_LIST_NO_MATCH;
101       }
102    }
103 
104    if (inexact_match)
105       return PARAMETER_LIST_INEXACT_MATCH;
106    else
107       return PARAMETER_LIST_EXACT_MATCH;
108 }
109 
110 
111 /* Classes of parameter match, sorted (mostly) best matches first.
112  * See is_better_parameter_match() below for the exceptions.
113  * */
114 typedef enum {
115    PARAMETER_EXACT_MATCH,
116    PARAMETER_FLOAT_TO_DOUBLE,
117    PARAMETER_INT_TO_FLOAT,
118    PARAMETER_INT_TO_DOUBLE,
119    PARAMETER_OTHER_CONVERSION,
120 } parameter_match_t;
121 
122 
123 static parameter_match_t
get_parameter_match_type(const nir_parameter * param,const nir_parameter * actual)124 get_parameter_match_type(const nir_parameter *param,
125                          const nir_parameter *actual)
126 {
127    const struct glsl_type *from_type;
128    const struct glsl_type *to_type;
129 
130    if (param->mode == nir_var_function_out) {
131       from_type = param->type;
132       to_type = actual->type;
133    } else {
134       from_type = actual->type;
135       to_type = param->type;
136    }
137 
138    if (from_type == to_type)
139       return PARAMETER_EXACT_MATCH;
140 
141    if (glsl_type_is_double(to_type)) {
142       if (glsl_type_is_float(from_type))
143          return PARAMETER_FLOAT_TO_DOUBLE;
144       return PARAMETER_INT_TO_DOUBLE;
145    }
146 
147    if (glsl_type_is_float(to_type))
148       return PARAMETER_INT_TO_FLOAT;
149 
150    /* int -> uint and any other oddball conversions */
151    return PARAMETER_OTHER_CONVERSION;
152 }
153 
154 /* From section 6.1 of the GLSL 4.00 spec (and the ARB_gpu_shader5 spec):
155  *
156  * 1. An exact match is better than a match involving any implicit
157  * conversion.
158  *
159  * 2. A match involving an implicit conversion from float to double
160  * is better than match involving any other implicit conversion.
161  *
162  * [XXX: Not in GLSL 4.0: Only in ARB_gpu_shader5:
163  * 3. A match involving an implicit conversion from either int or uint
164  * to float is better than a match involving an implicit conversion
165  * from either int or uint to double.]
166  *
167  * If none of the rules above apply to a particular pair of conversions,
168  * neither conversion is considered better than the other.
169  *
170  * --
171  *
172  * Notably, the int->uint conversion is *not* considered to be better
173  * or worse than int/uint->float or int/uint->double.
174  */
175 static bool
is_better_parameter_match(parameter_match_t a_match,parameter_match_t b_match)176 is_better_parameter_match(parameter_match_t a_match,
177                           parameter_match_t b_match)
178 {
179    if (a_match >= PARAMETER_INT_TO_FLOAT && b_match == PARAMETER_OTHER_CONVERSION)
180       return false;
181 
182    return a_match < b_match;
183 }
184 
185 /* From section 6.1 of the GLSL 4.00 spec (and the ARB_gpu_shader5 spec):
186  *
187  * "A function definition A is considered a better
188  * match than function definition B if:
189  *
190  *   * for at least one function argument, the conversion for that argument
191  *     in A is better than the corresponding conversion in B; and
192  *
193  *   * there is no function argument for which the conversion in B is better
194  *     than the corresponding conversion in A.
195  *
196  * If a single function definition is considered a better match than every
197  * other matching function definition, it will be used.  Otherwise, a
198  * semantic error occurs and the shader will fail to compile."
199  */
200 static bool
is_best_inexact_overload(nir_parameter * actual_parameters,unsigned num_parameters,nir_function ** matches,int num_matches,nir_function * sig)201 is_best_inexact_overload(nir_parameter *actual_parameters,
202                          unsigned num_parameters,
203                          nir_function **matches, int num_matches,
204                          nir_function *sig)
205 {
206 
207    for (nir_function **other = matches; other < matches + num_matches; other++) {
208       if (*other == sig)
209          continue;
210 
211       nir_parameter *node_a = sig->params;
212       nir_parameter *node_b = (*other)->params;
213 
214       bool better_for_some_parameter = false;
215 
216       for (unsigned i = 0; i < num_parameters; i++) {
217          parameter_match_t a_match =
218             get_parameter_match_type(&node_a[i], &actual_parameters[i]);
219          parameter_match_t b_match =
220             get_parameter_match_type(&node_b[i], &actual_parameters[i]);
221 
222          if (is_better_parameter_match(a_match, b_match))
223                better_for_some_parameter = true;
224 
225          if (is_better_parameter_match(b_match, a_match))
226                return false; /* B is better for this parameter */
227       }
228 
229       if (!better_for_some_parameter)
230          return false; /* A must be better than B for some parameter */
231    }
232 
233    return true;
234 }
235 
236 static nir_function *
choose_best_inexact_overload(nir_parameter * actual_parameters,unsigned num_parameters,nir_function ** matches,int num_matches,bool has_choose_best_inexact_overload)237 choose_best_inexact_overload(nir_parameter *actual_parameters,
238                              unsigned num_parameters,
239                              nir_function **matches, int num_matches,
240                              bool has_choose_best_inexact_overload)
241 {
242    if (num_matches == 0)
243       return NULL;
244 
245    if (num_matches == 1)
246       return *matches;
247 
248    if (!has_choose_best_inexact_overload)
249       return NULL;
250 
251    for (nir_function **sig = matches; sig < matches + num_matches; sig++) {
252       if (is_best_inexact_overload(actual_parameters, num_parameters,
253                                    matches, num_matches, *sig))
254          return *sig;
255    }
256 
257    /* no best candidate */
258    return NULL;
259 }
260 
261 static nir_function *
find_matching_signature(struct list_head * f_list,nir_parameter * parameters,unsigned num_parameters,bool has_implicit_conversions,bool has_implicit_int_to_uint_conversion)262 find_matching_signature(struct list_head *f_list,
263                         nir_parameter *parameters,
264                         unsigned num_parameters,
265                         bool has_implicit_conversions,
266                         bool has_implicit_int_to_uint_conversion)
267 {
268    nir_function **inexact_matches = NULL;
269    nir_function **inexact_matches_temp;
270    nir_function *match = NULL;
271    int num_inexact_matches = 0;
272 
273    /* From page 42 (page 49 of the PDF) of the GLSL 1.20 spec:
274     *
275     * "If an exact match is found, the other signatures are ignored, and
276     *  the exact match is used.  Otherwise, if no exact match is found, then
277     *  the implicit conversions in Section 4.1.10 "Implicit Conversions" will
278     *  be applied to the calling arguments if this can make their types match
279     *  a signature.  In this case, it is a semantic error if there are
280     *  multiple ways to apply these conversions to the actual arguments of a
281     *  call such that the call can be made to match multiple signatures."
282     */
283    list_for_each_entry(struct function_sig, sig, f_list, node) {
284       switch (parameter_lists_match(has_implicit_conversions,
285                                     has_implicit_int_to_uint_conversion,
286                                     sig->func->params, sig->func->num_params,
287                                     parameters, num_parameters)) {
288       case PARAMETER_LIST_EXACT_MATCH:
289          free(inexact_matches);
290          return sig->func;
291       case PARAMETER_LIST_INEXACT_MATCH:
292          /* Subroutine signatures must match exactly */
293          if (sig->func->is_subroutine)
294             continue;
295 
296          inexact_matches_temp = (nir_function **)
297                realloc(inexact_matches,
298                        sizeof(*inexact_matches) *
299                        (num_inexact_matches + 1));
300 
301          inexact_matches = inexact_matches_temp;
302          inexact_matches[num_inexact_matches++] = sig->func;
303          continue;
304       case PARAMETER_LIST_NO_MATCH:
305          continue;
306       default:
307          assert(false);
308          return NULL;
309       }
310    }
311 
312    match = choose_best_inexact_overload(parameters, num_parameters,
313                                         inexact_matches, num_inexact_matches,
314                                         has_implicit_int_to_uint_conversion);
315 
316    free(inexact_matches);
317    return match;
318 }
319 
320 static nir_function *
clone_function(struct hash_table * remap_table,const nir_function * fxn,nir_shader * ns)321 clone_function(struct hash_table *remap_table,
322                const nir_function *fxn, nir_shader *ns)
323 {
324    nir_function *nfxn = nir_function_clone(ns, fxn);
325    /* Needed for call instructions */
326    _mesa_hash_table_insert(remap_table, fxn, nfxn);
327 
328    return nfxn;
329 }
330 
331 bool
gl_nir_link_function_calls(struct gl_shader_program * prog,struct gl_shader * main,struct gl_linked_shader * linked_sh,struct gl_shader ** shader_list,unsigned num_shaders)332 gl_nir_link_function_calls(struct gl_shader_program *prog,
333                            struct gl_shader *main,
334                            struct gl_linked_shader *linked_sh,
335                            struct gl_shader **shader_list,
336                            unsigned num_shaders)
337 {
338    void *mem_ctx = ralloc_context(NULL);
339    struct hash_table *var_lookup = _mesa_string_hash_table_create(mem_ctx);
340    struct hash_table *func_lookup = _mesa_string_hash_table_create(mem_ctx);
341    struct hash_table *remap_table = _mesa_pointer_hash_table_create(mem_ctx);
342 
343    nir_foreach_variable_in_shader(var, linked_sh->Program->nir) {
344       _mesa_hash_table_insert(var_lookup, var->name, var);
345    }
346 
347    nir_foreach_function(func, linked_sh->Program->nir) {
348       if (!func->impl)
349          continue;
350 
351       struct hash_entry *e = _mesa_hash_table_search(func_lookup, func->name);
352       if (e) {
353          struct list_head *f_list = (struct list_head *) e->data;
354 
355          nir_function *f = find_matching_signature(f_list, func->params,
356                                                    func->num_params,
357                                                    main->has_implicit_conversions,
358                                                    main->has_implicit_int_to_uint_conversion);
359          if (!f) {
360             struct function_sig *func_sig = ralloc(mem_ctx, struct function_sig);
361             func_sig->func = func;
362             list_add(&func_sig->node, f_list);
363          }
364       } else {
365          struct list_head *func_list = ralloc(mem_ctx, struct list_head);
366          list_inithead(func_list);
367 
368          struct function_sig *func_sig = ralloc(mem_ctx, struct function_sig);
369          func_sig->func = func;
370          list_add(&func_sig->node, func_list);
371          _mesa_hash_table_insert(func_lookup, func->name, func_list);
372       }
373    }
374 
375    for (unsigned i = 0; i < num_shaders; i++) {
376       /* Skip shader object with main function as we have already cloned the
377        * full shader.
378        */
379       if (main == shader_list[i])
380          continue;
381 
382       /* Before cloning the shader check the lookup table to see if globals
383        * have already been seen in a previous shader, if so update the remap
384        * table.
385        */
386       nir_foreach_variable_in_shader(var, shader_list[i]->nir) {
387          struct hash_entry *e =
388             _mesa_hash_table_search(var_lookup, var->name);
389          if (e) {
390             _mesa_hash_table_insert(remap_table, var, e->data);
391 
392             nir_variable *m_var = (nir_variable *) e->data;
393             if (glsl_type_is_array(var->type)) {
394                /* It is possible to have a global array declared in multiple
395                 * shaders without a size.  The array is implicitly sized by
396                 * the maximal access to it in *any* shader.  Because of this,
397                 * we need to track the maximal access to the array as linking
398                 * pulls more functions in that access the array.
399                 */
400                m_var->data.max_array_access =
401                   MAX2(var->data.max_array_access,
402                        m_var->data.max_array_access);
403 
404                if (glsl_array_size(m_var->type) == 0 &&
405                    glsl_array_size(var->type) != 0)
406                   m_var->type = var->type;
407             }
408             if (glsl_without_array(var->type) == var->interface_type) {
409                /* Similarly, we need implicit sizes of arrays within interface
410                 * blocks to be sized by the maximal access in *any* shader.
411                 */
412                int *linked_max_ifc_array_access = m_var->max_ifc_array_access;
413                int *ir_max_ifc_array_access = var->max_ifc_array_access;
414 
415                assert(linked_max_ifc_array_access != NULL);
416                assert(ir_max_ifc_array_access != NULL);
417 
418                for (unsigned j = 0; j < var->interface_type->length; j++) {
419                   linked_max_ifc_array_access[j] =
420                      MAX2(linked_max_ifc_array_access[j],
421                           ir_max_ifc_array_access[j]);
422                }
423             }
424          } else {
425             nir_variable *nvar =
426                nir_variable_clone(var, linked_sh->Program->nir);
427             _mesa_hash_table_insert(remap_table, var, nvar);
428             nir_shader_add_variable(linked_sh->Program->nir, nvar);
429             _mesa_hash_table_insert(var_lookup, var->name, nvar);
430          }
431       }
432 
433       /* Clone functions into our combined shader */
434       nir_foreach_function(func, shader_list[i]->nir) {
435          nir_function *f = NULL;
436 
437          /* Try to find the signature in one of the shaders that is being
438           * linked. If not found clone the function.
439           */
440          struct hash_entry *e = _mesa_hash_table_search(func_lookup, func->name);
441          if (e) {
442             struct list_head *f_list = (struct list_head *) e->data;
443 
444             f = find_matching_signature(f_list, func->params,
445                                         func->num_params,
446                                         false,
447                                         false);
448             if (!f) {
449                struct function_sig *func_sig = ralloc(mem_ctx, struct function_sig);
450                f = clone_function(remap_table, func, linked_sh->Program->nir);
451                func_sig->func = f;
452                if (func->impl)
453                   list_add(&func_sig->node, f_list);
454             } else {
455                _mesa_hash_table_insert(remap_table, func, f);
456             }
457          } else {
458             struct list_head *func_list = ralloc(mem_ctx, struct list_head);
459             list_inithead(func_list);
460 
461             struct function_sig *func_sig = ralloc(mem_ctx, struct function_sig);
462             f = clone_function(remap_table, func, linked_sh->Program->nir);
463             func_sig->func = f;
464             if (func->impl)
465                list_add(&func_sig->node, func_list);
466             _mesa_hash_table_insert(func_lookup, func->name, func_list);
467          }
468       }
469 
470       /* Now that all functions are cloned we can clone any function
471        * implementations. We can't do this in the previous loop above because
472        * glsl to nir places function declarations next to implementations i.e.
473        * we have lost any predeclared function signatures so we won't always
474        * find them in the remap table until they have all been processed.
475        */
476       nir_foreach_function(func, shader_list[i]->nir) {
477          if (func->impl) {
478             nir_function_impl *f_impl =
479                nir_function_impl_clone_remap_globals(linked_sh->Program->nir,
480                                                      func->impl, remap_table);
481 
482             struct hash_entry *e =
483                _mesa_hash_table_search(remap_table, func);
484             assert(e);
485 
486             nir_function *f = (nir_function *) e->data;
487 
488             assert(!f->impl);
489             nir_function_set_impl(f, f_impl);
490          }
491       }
492    }
493 
494    /* Now that all shaders have been combined together make sure all function
495     * calls can be resolved.
496     */
497    nir_foreach_function_impl(impl, linked_sh->Program->nir) {
498       nir_foreach_block(block, impl) {
499          nir_foreach_instr(instr, block) {
500             if (instr->type == nir_instr_type_call) {
501                nir_call_instr *call = nir_instr_as_call(instr);
502 
503                /* If this was already set at compile time don't try to set it
504                 * again.
505                 */
506                if (call->callee->impl)
507                   continue;
508 
509                struct hash_entry *e = _mesa_hash_table_search(func_lookup,
510                                                               call->callee->name);
511                if (e) {
512                   struct list_head *f_list = (struct list_head *) e->data;
513 
514                   nir_function *f =
515                      find_matching_signature(f_list, call->callee->params,
516                                              call->callee->num_params,
517                                              main->has_implicit_conversions,
518                                              main->has_implicit_int_to_uint_conversion);
519                   if (f)
520                      call->callee = f;
521                }
522 
523                if (!call->callee->impl) {
524                   linker_error(prog, "unresolved reference to function `%s'\n",
525                                call->callee->name);
526                   ralloc_free(mem_ctx);
527                   return false;
528                }
529             }
530          }
531       }
532    }
533 
534    /**
535     * Link all out variables on a single stage which are not
536     * directly used in a shader with the main function.
537     */
538    if (linked_sh->Stage != MESA_SHADER_FRAGMENT) {
539       for (unsigned i = 0; i < num_shaders; i++) {
540          /* Skip shader object with main function as we have already cloned
541           * the full shader, including shader outputs.
542           */
543          if (main == shader_list[i])
544             continue;
545 
546          nir_foreach_shader_out_variable(var, shader_list[i]->nir) {
547             struct hash_entry *e =
548                _mesa_hash_table_search(var_lookup, var->name);
549             if (e)
550                continue;
551 
552             nir_variable *nvar = nir_variable_clone(var, linked_sh->Program->nir);
553             nir_shader_add_variable(linked_sh->Program->nir, nvar);
554             _mesa_hash_table_insert(var_lookup, var->name, var);
555          }
556       }
557    }
558 
559 
560    /* Call fixup deref types as we may have set array sizes above */
561    nir_fixup_deref_types(linked_sh->Program->nir);
562 
563    ralloc_free(mem_ctx);
564 
565    return true;
566 }
567