/* * Copyright 2024 Valve Corporation * SPDX-License-Identifier: MIT */ #include "nir.h" /* * After going through the clang -> LLVM -> SPIR-V translator -> vtn pipes, * OpenCL kernel's end up translated to 2 nir_functions: * * - a "wrapper" function that is_entrypoint but not is_exported * - the "real" function that is_exported * * Confusingly, both functions have the same name. * * Also, workgroup size information is on the wrapper function only, so we can't * just ignore the wrappers. But inlining and removing non-exported would delete * the whole shader and lose that information. * * This pass is a silly solution to the silly problem: it looks for shadowed * function names, which can only come from these wrappers. It then exports the * wrappers and unexports the inner functions. After inlining and removing * non-exported functions, we're left with a single function per kernel with * workgroup size information preserved. * * While we're at it, we unexport _prefixed functions. This is an escape hatch * to allow defining `kernel`s that are not intended for export, to workaround * OpenCL limitations around `static kernel`s and shared local memory outside * `kernel`s. */ void nir_fixup_is_exported(nir_shader *nir) { struct set *seen = _mesa_set_create(NULL, _mesa_hash_string, _mesa_key_string_equal); struct set *shadowed = _mesa_set_create(NULL, _mesa_hash_string, _mesa_key_string_equal); nir_foreach_function(func, nir) { if (_mesa_set_search(seen, func->name)) { _mesa_set_add(shadowed, func->name); } else { _mesa_set_add(seen, func->name); } } nir_foreach_function(func, nir) { if (_mesa_set_search(shadowed, func->name)) { func->is_exported = func->is_entrypoint; } if (func->name[0] == '_') { func->is_exported = func->is_entrypoint = false; } } _mesa_set_destroy(seen, NULL); _mesa_set_destroy(shadowed, NULL); }