1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2020 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "nir.h" 25bf215546Sopenharmony_ci#include "nir_serialize.h" 26bf215546Sopenharmony_ci#include "nir_spirv.h" 27bf215546Sopenharmony_ci#include "util/mesa-sha1.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH 30bf215546Sopenharmony_ci#include <fcntl.h> 31bf215546Sopenharmony_ci#include <sys/types.h> 32bf215546Sopenharmony_ci#include <sys/stat.h> 33bf215546Sopenharmony_ci#include <sys/mman.h> 34bf215546Sopenharmony_ci#include <unistd.h> 35bf215546Sopenharmony_ci#endif 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_ZSTD 38bf215546Sopenharmony_ci#include <zstd.h> 39bf215546Sopenharmony_ci#endif 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_SPIRV 42bf215546Sopenharmony_ci#include "spirv-mesa3d-.spv.h" 43bf215546Sopenharmony_ci#endif 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_SPIRV64 46bf215546Sopenharmony_ci#include "spirv64-mesa3d-.spv.h" 47bf215546Sopenharmony_ci#endif 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_cistruct clc_file { 50bf215546Sopenharmony_ci unsigned bit_size; 51bf215546Sopenharmony_ci const char *static_data; 52bf215546Sopenharmony_ci size_t static_data_size; 53bf215546Sopenharmony_ci const char *sys_path; 54bf215546Sopenharmony_ci}; 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_cistatic const struct clc_file libclc_files[] = { 57bf215546Sopenharmony_ci { 58bf215546Sopenharmony_ci .bit_size = 32, 59bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_SPIRV 60bf215546Sopenharmony_ci .static_data = libclc_spirv_mesa3d_spv, 61bf215546Sopenharmony_ci .static_data_size = sizeof(libclc_spirv_mesa3d_spv), 62bf215546Sopenharmony_ci#endif 63bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH 64bf215546Sopenharmony_ci .sys_path = DYNAMIC_LIBCLC_PATH "spirv-mesa3d-.spv", 65bf215546Sopenharmony_ci#endif 66bf215546Sopenharmony_ci }, 67bf215546Sopenharmony_ci { 68bf215546Sopenharmony_ci .bit_size = 64, 69bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_SPIRV64 70bf215546Sopenharmony_ci .static_data = libclc_spirv64_mesa3d_spv, 71bf215546Sopenharmony_ci .static_data_size = sizeof(libclc_spirv64_mesa3d_spv), 72bf215546Sopenharmony_ci#endif 73bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH 74bf215546Sopenharmony_ci .sys_path = DYNAMIC_LIBCLC_PATH "spirv64-mesa3d-.spv", 75bf215546Sopenharmony_ci#endif 76bf215546Sopenharmony_ci }, 77bf215546Sopenharmony_ci}; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_cistatic const struct clc_file * 80bf215546Sopenharmony_ciget_libclc_file(unsigned ptr_bit_size) 81bf215546Sopenharmony_ci{ 82bf215546Sopenharmony_ci assert(ptr_bit_size == 32 || ptr_bit_size == 64); 83bf215546Sopenharmony_ci return &libclc_files[ptr_bit_size / 64]; 84bf215546Sopenharmony_ci} 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_cistruct clc_data { 87bf215546Sopenharmony_ci const struct clc_file *file; 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci unsigned char cache_key[20]; 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci int fd; 92bf215546Sopenharmony_ci const void *data; 93bf215546Sopenharmony_ci size_t size; 94bf215546Sopenharmony_ci}; 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_cistatic bool 97bf215546Sopenharmony_ciopen_clc_data(struct clc_data *clc, unsigned ptr_bit_size) 98bf215546Sopenharmony_ci{ 99bf215546Sopenharmony_ci memset(clc, 0, sizeof(*clc)); 100bf215546Sopenharmony_ci clc->file = get_libclc_file(ptr_bit_size); 101bf215546Sopenharmony_ci clc->fd = -1; 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci if (clc->file->static_data) { 104bf215546Sopenharmony_ci snprintf((char *)clc->cache_key, sizeof(clc->cache_key), 105bf215546Sopenharmony_ci "libclc-spirv%d", ptr_bit_size); 106bf215546Sopenharmony_ci return true; 107bf215546Sopenharmony_ci } 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH 110bf215546Sopenharmony_ci if (clc->file->sys_path != NULL) { 111bf215546Sopenharmony_ci int fd = open(clc->file->sys_path, O_RDONLY); 112bf215546Sopenharmony_ci if (fd < 0) 113bf215546Sopenharmony_ci return false; 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci struct stat stat; 116bf215546Sopenharmony_ci int ret = fstat(fd, &stat); 117bf215546Sopenharmony_ci if (ret < 0) { 118bf215546Sopenharmony_ci fprintf(stderr, "fstat failed on %s: %m\n", clc->file->sys_path); 119bf215546Sopenharmony_ci close(fd); 120bf215546Sopenharmony_ci return false; 121bf215546Sopenharmony_ci } 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci struct mesa_sha1 ctx; 124bf215546Sopenharmony_ci _mesa_sha1_init(&ctx); 125bf215546Sopenharmony_ci _mesa_sha1_update(&ctx, clc->file->sys_path, strlen(clc->file->sys_path)); 126bf215546Sopenharmony_ci _mesa_sha1_update(&ctx, &stat.st_mtim, sizeof(stat.st_mtim)); 127bf215546Sopenharmony_ci _mesa_sha1_final(&ctx, clc->cache_key); 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci clc->fd = fd; 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_ci return true; 132bf215546Sopenharmony_ci } 133bf215546Sopenharmony_ci#endif 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci return false; 136bf215546Sopenharmony_ci} 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci#define SPIRV_WORD_SIZE 4 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_cistatic bool 141bf215546Sopenharmony_cimap_clc_data(struct clc_data *clc) 142bf215546Sopenharmony_ci{ 143bf215546Sopenharmony_ci if (clc->file->static_data) { 144bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_ZSTD 145bf215546Sopenharmony_ci unsigned long long cmp_size = 146bf215546Sopenharmony_ci ZSTD_getFrameContentSize(clc->file->static_data, 147bf215546Sopenharmony_ci clc->file->static_data_size); 148bf215546Sopenharmony_ci if (cmp_size == ZSTD_CONTENTSIZE_UNKNOWN || 149bf215546Sopenharmony_ci cmp_size == ZSTD_CONTENTSIZE_ERROR) { 150bf215546Sopenharmony_ci fprintf(stderr, "Could not determine the decompressed size of the " 151bf215546Sopenharmony_ci "libclc SPIR-V\n"); 152bf215546Sopenharmony_ci return false; 153bf215546Sopenharmony_ci } 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci size_t frame_size = 156bf215546Sopenharmony_ci ZSTD_findFrameCompressedSize(clc->file->static_data, 157bf215546Sopenharmony_ci clc->file->static_data_size); 158bf215546Sopenharmony_ci if (ZSTD_isError(frame_size)) { 159bf215546Sopenharmony_ci fprintf(stderr, "Could not determine the size of the first ZSTD frame " 160bf215546Sopenharmony_ci "when decompressing libclc SPIR-V: %s\n", 161bf215546Sopenharmony_ci ZSTD_getErrorName(frame_size)); 162bf215546Sopenharmony_ci return false; 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci void *dest = malloc(cmp_size + 1); 166bf215546Sopenharmony_ci size_t size = ZSTD_decompress(dest, cmp_size, clc->file->static_data, 167bf215546Sopenharmony_ci frame_size); 168bf215546Sopenharmony_ci if (ZSTD_isError(size)) { 169bf215546Sopenharmony_ci free(dest); 170bf215546Sopenharmony_ci fprintf(stderr, "Error decompressing libclc SPIR-V: %s\n", 171bf215546Sopenharmony_ci ZSTD_getErrorName(size)); 172bf215546Sopenharmony_ci return false; 173bf215546Sopenharmony_ci } 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci clc->data = dest; 176bf215546Sopenharmony_ci clc->size = size; 177bf215546Sopenharmony_ci#else 178bf215546Sopenharmony_ci clc->data = clc->file->static_data; 179bf215546Sopenharmony_ci clc->size = clc->file->static_data_size; 180bf215546Sopenharmony_ci#endif 181bf215546Sopenharmony_ci return true; 182bf215546Sopenharmony_ci } 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH 185bf215546Sopenharmony_ci if (clc->file->sys_path != NULL) { 186bf215546Sopenharmony_ci off_t len = lseek(clc->fd, 0, SEEK_END); 187bf215546Sopenharmony_ci if (len % SPIRV_WORD_SIZE != 0) { 188bf215546Sopenharmony_ci fprintf(stderr, "File length isn't a multiple of the word size\n"); 189bf215546Sopenharmony_ci return false; 190bf215546Sopenharmony_ci } 191bf215546Sopenharmony_ci clc->size = len; 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ci clc->data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, clc->fd, 0); 194bf215546Sopenharmony_ci if (clc->data == MAP_FAILED) { 195bf215546Sopenharmony_ci fprintf(stderr, "Failed to mmap libclc SPIR-V: %m\n"); 196bf215546Sopenharmony_ci return false; 197bf215546Sopenharmony_ci } 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci return true; 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci#endif 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci return true; 204bf215546Sopenharmony_ci} 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_cistatic void 207bf215546Sopenharmony_ciclose_clc_data(struct clc_data *clc) 208bf215546Sopenharmony_ci{ 209bf215546Sopenharmony_ci if (clc->file->static_data) { 210bf215546Sopenharmony_ci#ifdef HAVE_STATIC_LIBCLC_ZSTD 211bf215546Sopenharmony_ci free((void *)clc->data); 212bf215546Sopenharmony_ci#endif 213bf215546Sopenharmony_ci return; 214bf215546Sopenharmony_ci } 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci#ifdef DYNAMIC_LIBCLC_PATH 217bf215546Sopenharmony_ci if (clc->file->sys_path != NULL) { 218bf215546Sopenharmony_ci if (clc->data) 219bf215546Sopenharmony_ci munmap((void *)clc->data, clc->size); 220bf215546Sopenharmony_ci close(clc->fd); 221bf215546Sopenharmony_ci } 222bf215546Sopenharmony_ci#endif 223bf215546Sopenharmony_ci} 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci/** Returns true if libclc is found 226bf215546Sopenharmony_ci * 227bf215546Sopenharmony_ci * If libclc is compiled in statically, this always returns true. If we 228bf215546Sopenharmony_ci * depend on a dynamic libclc, this opens and tries to stat the file. 229bf215546Sopenharmony_ci */ 230bf215546Sopenharmony_cibool 231bf215546Sopenharmony_cinir_can_find_libclc(unsigned ptr_bit_size) 232bf215546Sopenharmony_ci{ 233bf215546Sopenharmony_ci struct clc_data clc; 234bf215546Sopenharmony_ci if (open_clc_data(&clc, ptr_bit_size)) { 235bf215546Sopenharmony_ci close_clc_data(&clc); 236bf215546Sopenharmony_ci return true; 237bf215546Sopenharmony_ci } else { 238bf215546Sopenharmony_ci return false; 239bf215546Sopenharmony_ci } 240bf215546Sopenharmony_ci} 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci/** Adds generic pointer variants of libclc functions 243bf215546Sopenharmony_ci * 244bf215546Sopenharmony_ci * Libclc currently doesn't contain generic variants for a bunch of functions 245bf215546Sopenharmony_ci * like `frexp` but the OpenCL spec with generic pointers requires them. We 246bf215546Sopenharmony_ci * really should fix libclc but, in the mean time, we can easily duplicate 247bf215546Sopenharmony_ci * every function that works on global memory and make it also work on generic 248bf215546Sopenharmony_ci * memory. 249bf215546Sopenharmony_ci */ 250bf215546Sopenharmony_cistatic void 251bf215546Sopenharmony_cilibclc_add_generic_variants(nir_shader *shader) 252bf215546Sopenharmony_ci{ 253bf215546Sopenharmony_ci nir_foreach_function(func, shader) { 254bf215546Sopenharmony_ci /* These don't need generic variants */ 255bf215546Sopenharmony_ci if (strstr(func->name, "async_work_group_strided_copy")) 256bf215546Sopenharmony_ci continue; 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci char *U3AS1 = strstr(func->name, "U3AS1"); 259bf215546Sopenharmony_ci if (U3AS1 == NULL) 260bf215546Sopenharmony_ci continue; 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ci ptrdiff_t offset_1 = U3AS1 - func->name + 4; 263bf215546Sopenharmony_ci assert(offset_1 < strlen(func->name) && func->name[offset_1] == '1'); 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci char *generic_name = ralloc_strdup(shader, func->name); 266bf215546Sopenharmony_ci assert(generic_name[offset_1] == '1'); 267bf215546Sopenharmony_ci generic_name[offset_1] = '4'; 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci nir_function *gfunc = nir_function_create(shader, generic_name); 270bf215546Sopenharmony_ci gfunc->num_params = func->num_params; 271bf215546Sopenharmony_ci gfunc->params = ralloc_array(shader, nir_parameter, gfunc->num_params); 272bf215546Sopenharmony_ci for (unsigned i = 0; i < gfunc->num_params; i++) 273bf215546Sopenharmony_ci gfunc->params[i] = func->params[i]; 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci gfunc->impl = nir_function_impl_clone(shader, func->impl); 276bf215546Sopenharmony_ci gfunc->impl->function = gfunc; 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci /* Rewrite any global pointers to generic */ 279bf215546Sopenharmony_ci nir_foreach_block(block, gfunc->impl) { 280bf215546Sopenharmony_ci nir_foreach_instr(instr, block) { 281bf215546Sopenharmony_ci if (instr->type != nir_instr_type_deref) 282bf215546Sopenharmony_ci continue; 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci nir_deref_instr *deref = nir_instr_as_deref(instr); 285bf215546Sopenharmony_ci if (!nir_deref_mode_may_be(deref, nir_var_mem_global)) 286bf215546Sopenharmony_ci continue; 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci assert(deref->type != nir_deref_type_var); 289bf215546Sopenharmony_ci assert(nir_deref_mode_is(deref, nir_var_mem_global)); 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci deref->modes = nir_var_mem_generic; 292bf215546Sopenharmony_ci } 293bf215546Sopenharmony_ci } 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci nir_metadata_preserve(gfunc->impl, nir_metadata_none); 296bf215546Sopenharmony_ci } 297bf215546Sopenharmony_ci} 298bf215546Sopenharmony_ci 299bf215546Sopenharmony_cinir_shader * 300bf215546Sopenharmony_cinir_load_libclc_shader(unsigned ptr_bit_size, 301bf215546Sopenharmony_ci struct disk_cache *disk_cache, 302bf215546Sopenharmony_ci const struct spirv_to_nir_options *spirv_options, 303bf215546Sopenharmony_ci const nir_shader_compiler_options *nir_options) 304bf215546Sopenharmony_ci{ 305bf215546Sopenharmony_ci assert(ptr_bit_size == 306bf215546Sopenharmony_ci nir_address_format_bit_size(spirv_options->global_addr_format)); 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci struct clc_data clc; 309bf215546Sopenharmony_ci if (!open_clc_data(&clc, ptr_bit_size)) 310bf215546Sopenharmony_ci return NULL; 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE 313bf215546Sopenharmony_ci cache_key cache_key; 314bf215546Sopenharmony_ci if (disk_cache) { 315bf215546Sopenharmony_ci disk_cache_compute_key(disk_cache, clc.cache_key, 316bf215546Sopenharmony_ci sizeof(clc.cache_key), cache_key); 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci size_t buffer_size; 319bf215546Sopenharmony_ci uint8_t *buffer = disk_cache_get(disk_cache, cache_key, &buffer_size); 320bf215546Sopenharmony_ci if (buffer) { 321bf215546Sopenharmony_ci struct blob_reader blob; 322bf215546Sopenharmony_ci blob_reader_init(&blob, buffer, buffer_size); 323bf215546Sopenharmony_ci nir_shader *nir = nir_deserialize(NULL, nir_options, &blob); 324bf215546Sopenharmony_ci free(buffer); 325bf215546Sopenharmony_ci close_clc_data(&clc); 326bf215546Sopenharmony_ci return nir; 327bf215546Sopenharmony_ci } 328bf215546Sopenharmony_ci } 329bf215546Sopenharmony_ci#endif 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci if (!map_clc_data(&clc)) { 332bf215546Sopenharmony_ci close_clc_data(&clc); 333bf215546Sopenharmony_ci return NULL; 334bf215546Sopenharmony_ci } 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci struct spirv_to_nir_options spirv_lib_options = *spirv_options; 337bf215546Sopenharmony_ci spirv_lib_options.create_library = true; 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_ci assert(clc.size % SPIRV_WORD_SIZE == 0); 340bf215546Sopenharmony_ci nir_shader *nir = spirv_to_nir(clc.data, clc.size / SPIRV_WORD_SIZE, 341bf215546Sopenharmony_ci NULL, 0, MESA_SHADER_KERNEL, NULL, 342bf215546Sopenharmony_ci &spirv_lib_options, nir_options); 343bf215546Sopenharmony_ci nir_validate_shader(nir, "after nir_load_clc_shader"); 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci /* nir_inline_libclc will assume that the functions in this shader are 346bf215546Sopenharmony_ci * already ready to lower. This means we need to inline any function_temp 347bf215546Sopenharmony_ci * initializers and lower any early returns. 348bf215546Sopenharmony_ci */ 349bf215546Sopenharmony_ci nir->info.internal = true; 350bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp); 351bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_lower_returns); 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci NIR_PASS_V(nir, libclc_add_generic_variants); 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci /* TODO: One day, we may want to run some optimizations on the libclc 356bf215546Sopenharmony_ci * shader once and cache them to save time in each shader call. 357bf215546Sopenharmony_ci */ 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE 360bf215546Sopenharmony_ci if (disk_cache) { 361bf215546Sopenharmony_ci struct blob blob; 362bf215546Sopenharmony_ci blob_init(&blob); 363bf215546Sopenharmony_ci nir_serialize(&blob, nir, false); 364bf215546Sopenharmony_ci disk_cache_put(disk_cache, cache_key, blob.data, blob.size, NULL); 365bf215546Sopenharmony_ci } 366bf215546Sopenharmony_ci#endif 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_ci close_clc_data(&clc); 369bf215546Sopenharmony_ci return nir; 370bf215546Sopenharmony_ci} 371