1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © Microsoft 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/nir.h" 25bf215546Sopenharmony_ci#include "nir/nir_serialize.h" 26bf215546Sopenharmony_ci#include "glsl_types.h" 27bf215546Sopenharmony_ci#include "nir_types.h" 28bf215546Sopenharmony_ci#include "clc.h" 29bf215546Sopenharmony_ci#include "clc_helpers.h" 30bf215546Sopenharmony_ci#include "spirv/nir_spirv.h" 31bf215546Sopenharmony_ci#include "util/u_debug.h" 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#include <stdlib.h> 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_cienum clc_debug_flags { 36bf215546Sopenharmony_ci CLC_DEBUG_DUMP_SPIRV = 1 << 0, 37bf215546Sopenharmony_ci CLC_DEBUG_VERBOSE = 1 << 1, 38bf215546Sopenharmony_ci}; 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_cistatic const struct debug_named_value clc_debug_options[] = { 41bf215546Sopenharmony_ci { "dump_spirv", CLC_DEBUG_DUMP_SPIRV, "Dump spirv blobs" }, 42bf215546Sopenharmony_ci { "verbose", CLC_DEBUG_VERBOSE, NULL }, 43bf215546Sopenharmony_ci DEBUG_NAMED_VALUE_END 44bf215546Sopenharmony_ci}; 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ciDEBUG_GET_ONCE_FLAGS_OPTION(debug_clc, "CLC_DEBUG", clc_debug_options, 0) 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cistatic void 49bf215546Sopenharmony_ciclc_print_kernels_info(const struct clc_parsed_spirv *obj) 50bf215546Sopenharmony_ci{ 51bf215546Sopenharmony_ci fprintf(stdout, "Kernels:\n"); 52bf215546Sopenharmony_ci for (unsigned i = 0; i < obj->num_kernels; i++) { 53bf215546Sopenharmony_ci const struct clc_kernel_arg *args = obj->kernels[i].args; 54bf215546Sopenharmony_ci bool first = true; 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci fprintf(stdout, "\tvoid %s(", obj->kernels[i].name); 57bf215546Sopenharmony_ci for (unsigned j = 0; j < obj->kernels[i].num_args; j++) { 58bf215546Sopenharmony_ci if (!first) 59bf215546Sopenharmony_ci fprintf(stdout, ", "); 60bf215546Sopenharmony_ci else 61bf215546Sopenharmony_ci first = false; 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci switch (args[j].address_qualifier) { 64bf215546Sopenharmony_ci case CLC_KERNEL_ARG_ADDRESS_GLOBAL: 65bf215546Sopenharmony_ci fprintf(stdout, "__global "); 66bf215546Sopenharmony_ci break; 67bf215546Sopenharmony_ci case CLC_KERNEL_ARG_ADDRESS_LOCAL: 68bf215546Sopenharmony_ci fprintf(stdout, "__local "); 69bf215546Sopenharmony_ci break; 70bf215546Sopenharmony_ci case CLC_KERNEL_ARG_ADDRESS_CONSTANT: 71bf215546Sopenharmony_ci fprintf(stdout, "__constant "); 72bf215546Sopenharmony_ci break; 73bf215546Sopenharmony_ci default: 74bf215546Sopenharmony_ci break; 75bf215546Sopenharmony_ci } 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci if (args[j].type_qualifier & CLC_KERNEL_ARG_TYPE_VOLATILE) 78bf215546Sopenharmony_ci fprintf(stdout, "volatile "); 79bf215546Sopenharmony_ci if (args[j].type_qualifier & CLC_KERNEL_ARG_TYPE_CONST) 80bf215546Sopenharmony_ci fprintf(stdout, "const "); 81bf215546Sopenharmony_ci if (args[j].type_qualifier & CLC_KERNEL_ARG_TYPE_RESTRICT) 82bf215546Sopenharmony_ci fprintf(stdout, "restrict "); 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci fprintf(stdout, "%s %s", args[j].type_name, args[j].name); 85bf215546Sopenharmony_ci } 86bf215546Sopenharmony_ci fprintf(stdout, ");\n"); 87bf215546Sopenharmony_ci } 88bf215546Sopenharmony_ci} 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_cistatic void 91bf215546Sopenharmony_ciclc_libclc_optimize(nir_shader *s) 92bf215546Sopenharmony_ci{ 93bf215546Sopenharmony_ci bool progress; 94bf215546Sopenharmony_ci do { 95bf215546Sopenharmony_ci progress = false; 96bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_split_var_copies); 97bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_copy_prop_vars); 98bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_lower_var_copies); 99bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_lower_vars_to_ssa); 100bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_copy_prop); 101bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_remove_phis); 102bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_dce); 103bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_if, nir_opt_if_aggressive_last_continue | nir_opt_if_optimize_phi_true_false); 104bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_dead_cf); 105bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_cse); 106bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true); 107bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_algebraic); 108bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_constant_folding); 109bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_undef); 110bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_lower_undef_to_zero); 111bf215546Sopenharmony_ci NIR_PASS(progress, s, nir_opt_deref); 112bf215546Sopenharmony_ci } while (progress); 113bf215546Sopenharmony_ci} 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_cistruct clc_libclc { 116bf215546Sopenharmony_ci const nir_shader *libclc_nir; 117bf215546Sopenharmony_ci}; 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_cistruct clc_libclc * 120bf215546Sopenharmony_ciclc_libclc_new(const struct clc_logger *logger, const struct clc_libclc_options *options) 121bf215546Sopenharmony_ci{ 122bf215546Sopenharmony_ci struct clc_libclc *ctx = rzalloc(NULL, struct clc_libclc); 123bf215546Sopenharmony_ci if (!ctx) { 124bf215546Sopenharmony_ci clc_error(logger, "D3D12: failed to allocate a clc_libclc"); 125bf215546Sopenharmony_ci return NULL; 126bf215546Sopenharmony_ci } 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci const struct spirv_to_nir_options libclc_spirv_options = { 129bf215546Sopenharmony_ci .environment = NIR_SPIRV_OPENCL, 130bf215546Sopenharmony_ci .create_library = true, 131bf215546Sopenharmony_ci .constant_addr_format = nir_address_format_32bit_index_offset_pack64, 132bf215546Sopenharmony_ci .global_addr_format = nir_address_format_32bit_index_offset_pack64, 133bf215546Sopenharmony_ci .shared_addr_format = nir_address_format_32bit_offset_as_64bit, 134bf215546Sopenharmony_ci .temp_addr_format = nir_address_format_32bit_offset_as_64bit, 135bf215546Sopenharmony_ci .float_controls_execution_mode = FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP32, 136bf215546Sopenharmony_ci .caps = { 137bf215546Sopenharmony_ci .address = true, 138bf215546Sopenharmony_ci .float64 = true, 139bf215546Sopenharmony_ci .int8 = true, 140bf215546Sopenharmony_ci .int16 = true, 141bf215546Sopenharmony_ci .int64 = true, 142bf215546Sopenharmony_ci .kernel = true, 143bf215546Sopenharmony_ci }, 144bf215546Sopenharmony_ci }; 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci glsl_type_singleton_init_or_ref(); 147bf215546Sopenharmony_ci nir_shader *s = nir_load_libclc_shader(64, NULL, &libclc_spirv_options, options->nir_options); 148bf215546Sopenharmony_ci if (!s) { 149bf215546Sopenharmony_ci clc_error(logger, "D3D12: spirv_to_nir failed on libclc blob"); 150bf215546Sopenharmony_ci ralloc_free(ctx); 151bf215546Sopenharmony_ci return NULL; 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci if (options && options->optimize) 155bf215546Sopenharmony_ci clc_libclc_optimize(s); 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci ralloc_steal(ctx, s); 158bf215546Sopenharmony_ci ctx->libclc_nir = s; 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci return ctx; 161bf215546Sopenharmony_ci} 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_civoid clc_free_libclc(struct clc_libclc *ctx) 164bf215546Sopenharmony_ci{ 165bf215546Sopenharmony_ci ralloc_free(ctx); 166bf215546Sopenharmony_ci glsl_type_singleton_decref(); 167bf215546Sopenharmony_ci} 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ciconst nir_shader *clc_libclc_get_clc_shader(struct clc_libclc *ctx) 170bf215546Sopenharmony_ci{ 171bf215546Sopenharmony_ci return ctx->libclc_nir; 172bf215546Sopenharmony_ci} 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_civoid clc_libclc_serialize(struct clc_libclc *context, 175bf215546Sopenharmony_ci void **serialized, 176bf215546Sopenharmony_ci size_t *serialized_size) 177bf215546Sopenharmony_ci{ 178bf215546Sopenharmony_ci struct blob tmp; 179bf215546Sopenharmony_ci blob_init(&tmp); 180bf215546Sopenharmony_ci nir_serialize(&tmp, context->libclc_nir, true); 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci blob_finish_get_buffer(&tmp, serialized, serialized_size); 183bf215546Sopenharmony_ci} 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_civoid clc_libclc_free_serialized(void *serialized) 186bf215546Sopenharmony_ci{ 187bf215546Sopenharmony_ci free(serialized); 188bf215546Sopenharmony_ci} 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_cistruct clc_libclc * 191bf215546Sopenharmony_ciclc_libclc_deserialize(const void *serialized, size_t serialized_size) 192bf215546Sopenharmony_ci{ 193bf215546Sopenharmony_ci struct clc_libclc *ctx = rzalloc(NULL, struct clc_libclc); 194bf215546Sopenharmony_ci if (!ctx) { 195bf215546Sopenharmony_ci return NULL; 196bf215546Sopenharmony_ci } 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci glsl_type_singleton_init_or_ref(); 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci struct blob_reader tmp; 201bf215546Sopenharmony_ci blob_reader_init(&tmp, serialized, serialized_size); 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci nir_shader *s = nir_deserialize(NULL, NULL, &tmp); 204bf215546Sopenharmony_ci if (!s) { 205bf215546Sopenharmony_ci ralloc_free(ctx); 206bf215546Sopenharmony_ci return NULL; 207bf215546Sopenharmony_ci } 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci ralloc_steal(ctx, s); 210bf215546Sopenharmony_ci ctx->libclc_nir = s; 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci return ctx; 213bf215546Sopenharmony_ci} 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_cibool 216bf215546Sopenharmony_ciclc_compile_c_to_spir(const struct clc_compile_args *args, 217bf215546Sopenharmony_ci const struct clc_logger *logger, 218bf215546Sopenharmony_ci struct clc_binary *out_spir) 219bf215546Sopenharmony_ci{ 220bf215546Sopenharmony_ci return clc_c_to_spir(args, logger, out_spir) >= 0; 221bf215546Sopenharmony_ci} 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_civoid 224bf215546Sopenharmony_ciclc_free_spir(struct clc_binary *spir) 225bf215546Sopenharmony_ci{ 226bf215546Sopenharmony_ci clc_free_spir_binary(spir); 227bf215546Sopenharmony_ci} 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_cibool 230bf215546Sopenharmony_ciclc_compile_spir_to_spirv(const struct clc_binary *in_spir, 231bf215546Sopenharmony_ci const struct clc_logger *logger, 232bf215546Sopenharmony_ci struct clc_binary *out_spirv) 233bf215546Sopenharmony_ci{ 234bf215546Sopenharmony_ci if (clc_spir_to_spirv(in_spir, logger, out_spirv) < 0) 235bf215546Sopenharmony_ci return false; 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci if (debug_get_option_debug_clc() & CLC_DEBUG_DUMP_SPIRV) 238bf215546Sopenharmony_ci clc_dump_spirv(out_spirv, stdout); 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci return true; 241bf215546Sopenharmony_ci} 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_civoid 244bf215546Sopenharmony_ciclc_free_spirv(struct clc_binary *spirv) 245bf215546Sopenharmony_ci{ 246bf215546Sopenharmony_ci clc_free_spirv_binary(spirv); 247bf215546Sopenharmony_ci} 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_cibool 250bf215546Sopenharmony_ciclc_compile_c_to_spirv(const struct clc_compile_args *args, 251bf215546Sopenharmony_ci const struct clc_logger *logger, 252bf215546Sopenharmony_ci struct clc_binary *out_spirv) 253bf215546Sopenharmony_ci{ 254bf215546Sopenharmony_ci if (clc_c_to_spirv(args, logger, out_spirv) < 0) 255bf215546Sopenharmony_ci return false; 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci if (debug_get_option_debug_clc() & CLC_DEBUG_DUMP_SPIRV) 258bf215546Sopenharmony_ci clc_dump_spirv(out_spirv, stdout); 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci return true; 261bf215546Sopenharmony_ci} 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_cibool 264bf215546Sopenharmony_ciclc_link_spirv(const struct clc_linker_args *args, 265bf215546Sopenharmony_ci const struct clc_logger *logger, 266bf215546Sopenharmony_ci struct clc_binary *out_spirv) 267bf215546Sopenharmony_ci{ 268bf215546Sopenharmony_ci if (clc_link_spirv_binaries(args, logger, out_spirv) < 0) 269bf215546Sopenharmony_ci return false; 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci if (debug_get_option_debug_clc() & CLC_DEBUG_DUMP_SPIRV) 272bf215546Sopenharmony_ci clc_dump_spirv(out_spirv, stdout); 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci return true; 275bf215546Sopenharmony_ci} 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_cibool 278bf215546Sopenharmony_ciclc_parse_spirv(const struct clc_binary *in_spirv, 279bf215546Sopenharmony_ci const struct clc_logger *logger, 280bf215546Sopenharmony_ci struct clc_parsed_spirv *out_data) 281bf215546Sopenharmony_ci{ 282bf215546Sopenharmony_ci if (!clc_spirv_get_kernels_info(in_spirv, 283bf215546Sopenharmony_ci &out_data->kernels, 284bf215546Sopenharmony_ci &out_data->num_kernels, 285bf215546Sopenharmony_ci &out_data->spec_constants, 286bf215546Sopenharmony_ci &out_data->num_spec_constants, 287bf215546Sopenharmony_ci logger)) 288bf215546Sopenharmony_ci return false; 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci if (debug_get_option_debug_clc() & CLC_DEBUG_VERBOSE) 291bf215546Sopenharmony_ci clc_print_kernels_info(out_data); 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci return true; 294bf215546Sopenharmony_ci} 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_civoid clc_free_parsed_spirv(struct clc_parsed_spirv *data) 297bf215546Sopenharmony_ci{ 298bf215546Sopenharmony_ci clc_free_kernels_info(data->kernels, data->num_kernels); 299bf215546Sopenharmony_ci} 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_cibool 302bf215546Sopenharmony_ciclc_specialize_spirv(const struct clc_binary *in_spirv, 303bf215546Sopenharmony_ci const struct clc_parsed_spirv *parsed_data, 304bf215546Sopenharmony_ci const struct clc_spirv_specialization_consts *consts, 305bf215546Sopenharmony_ci struct clc_binary *out_spirv) 306bf215546Sopenharmony_ci{ 307bf215546Sopenharmony_ci if (!clc_spirv_specialize(in_spirv, parsed_data, consts, out_spirv)) 308bf215546Sopenharmony_ci return false; 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci if (debug_get_option_debug_clc() & CLC_DEBUG_DUMP_SPIRV) 311bf215546Sopenharmony_ci clc_dump_spirv(out_spirv, stdout); 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci return true; 314bf215546Sopenharmony_ci} 315