clc.c revision 7ec681f3
17ec681f3Smrg/* 27ec681f3Smrg * Copyright © Microsoft Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include "nir/nir.h" 257ec681f3Smrg#include "nir/nir_serialize.h" 267ec681f3Smrg#include "glsl_types.h" 277ec681f3Smrg#include "nir_types.h" 287ec681f3Smrg#include "clc.h" 297ec681f3Smrg#include "clc_helpers.h" 307ec681f3Smrg#include "spirv/nir_spirv.h" 317ec681f3Smrg#include "util/u_debug.h" 327ec681f3Smrg 337ec681f3Smrg#include <stdlib.h> 347ec681f3Smrg 357ec681f3Smrgenum clc_debug_flags { 367ec681f3Smrg CLC_DEBUG_DUMP_SPIRV = 1 << 0, 377ec681f3Smrg CLC_DEBUG_VERBOSE = 1 << 1, 387ec681f3Smrg}; 397ec681f3Smrg 407ec681f3Smrgstatic const struct debug_named_value clc_debug_options[] = { 417ec681f3Smrg { "dump_spirv", CLC_DEBUG_DUMP_SPIRV, "Dump spirv blobs" }, 427ec681f3Smrg { "verbose", CLC_DEBUG_VERBOSE, NULL }, 437ec681f3Smrg DEBUG_NAMED_VALUE_END 447ec681f3Smrg}; 457ec681f3Smrg 467ec681f3SmrgDEBUG_GET_ONCE_FLAGS_OPTION(debug_clc, "CLC_DEBUG", clc_debug_options, 0) 477ec681f3Smrg 487ec681f3Smrgstatic void 497ec681f3Smrgclc_print_kernels_info(const struct clc_parsed_spirv *obj) 507ec681f3Smrg{ 517ec681f3Smrg fprintf(stdout, "Kernels:\n"); 527ec681f3Smrg for (unsigned i = 0; i < obj->num_kernels; i++) { 537ec681f3Smrg const struct clc_kernel_arg *args = obj->kernels[i].args; 547ec681f3Smrg bool first = true; 557ec681f3Smrg 567ec681f3Smrg fprintf(stdout, "\tvoid %s(", obj->kernels[i].name); 577ec681f3Smrg for (unsigned j = 0; j < obj->kernels[i].num_args; j++) { 587ec681f3Smrg if (!first) 597ec681f3Smrg fprintf(stdout, ", "); 607ec681f3Smrg else 617ec681f3Smrg first = false; 627ec681f3Smrg 637ec681f3Smrg switch (args[j].address_qualifier) { 647ec681f3Smrg case CLC_KERNEL_ARG_ADDRESS_GLOBAL: 657ec681f3Smrg fprintf(stdout, "__global "); 667ec681f3Smrg break; 677ec681f3Smrg case CLC_KERNEL_ARG_ADDRESS_LOCAL: 687ec681f3Smrg fprintf(stdout, "__local "); 697ec681f3Smrg break; 707ec681f3Smrg case CLC_KERNEL_ARG_ADDRESS_CONSTANT: 717ec681f3Smrg fprintf(stdout, "__constant "); 727ec681f3Smrg break; 737ec681f3Smrg default: 747ec681f3Smrg break; 757ec681f3Smrg } 767ec681f3Smrg 777ec681f3Smrg if (args[j].type_qualifier & CLC_KERNEL_ARG_TYPE_VOLATILE) 787ec681f3Smrg fprintf(stdout, "volatile "); 797ec681f3Smrg if (args[j].type_qualifier & CLC_KERNEL_ARG_TYPE_CONST) 807ec681f3Smrg fprintf(stdout, "const "); 817ec681f3Smrg if (args[j].type_qualifier & CLC_KERNEL_ARG_TYPE_RESTRICT) 827ec681f3Smrg fprintf(stdout, "restrict "); 837ec681f3Smrg 847ec681f3Smrg fprintf(stdout, "%s %s", args[j].type_name, args[j].name); 857ec681f3Smrg } 867ec681f3Smrg fprintf(stdout, ");\n"); 877ec681f3Smrg } 887ec681f3Smrg} 897ec681f3Smrg 907ec681f3Smrgstatic void 917ec681f3Smrgclc_libclc_optimize(nir_shader *s) 927ec681f3Smrg{ 937ec681f3Smrg bool progress; 947ec681f3Smrg do { 957ec681f3Smrg progress = false; 967ec681f3Smrg NIR_PASS(progress, s, nir_split_var_copies); 977ec681f3Smrg NIR_PASS(progress, s, nir_opt_copy_prop_vars); 987ec681f3Smrg NIR_PASS(progress, s, nir_lower_var_copies); 997ec681f3Smrg NIR_PASS(progress, s, nir_lower_vars_to_ssa); 1007ec681f3Smrg NIR_PASS(progress, s, nir_copy_prop); 1017ec681f3Smrg NIR_PASS(progress, s, nir_opt_remove_phis); 1027ec681f3Smrg NIR_PASS(progress, s, nir_opt_dce); 1037ec681f3Smrg NIR_PASS(progress, s, nir_opt_if, true); 1047ec681f3Smrg NIR_PASS(progress, s, nir_opt_dead_cf); 1057ec681f3Smrg NIR_PASS(progress, s, nir_opt_cse); 1067ec681f3Smrg NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true); 1077ec681f3Smrg NIR_PASS(progress, s, nir_opt_algebraic); 1087ec681f3Smrg NIR_PASS(progress, s, nir_opt_constant_folding); 1097ec681f3Smrg NIR_PASS(progress, s, nir_opt_undef); 1107ec681f3Smrg NIR_PASS(progress, s, nir_lower_undef_to_zero); 1117ec681f3Smrg NIR_PASS(progress, s, nir_opt_deref); 1127ec681f3Smrg } while (progress); 1137ec681f3Smrg} 1147ec681f3Smrg 1157ec681f3Smrgstruct clc_libclc { 1167ec681f3Smrg const nir_shader *libclc_nir; 1177ec681f3Smrg}; 1187ec681f3Smrg 1197ec681f3Smrgstruct clc_libclc * 1207ec681f3Smrgclc_libclc_new(const struct clc_logger *logger, const struct clc_libclc_options *options) 1217ec681f3Smrg{ 1227ec681f3Smrg struct clc_libclc *ctx = rzalloc(NULL, struct clc_libclc); 1237ec681f3Smrg if (!ctx) { 1247ec681f3Smrg clc_error(logger, "D3D12: failed to allocate a clc_libclc"); 1257ec681f3Smrg return NULL; 1267ec681f3Smrg } 1277ec681f3Smrg 1287ec681f3Smrg const struct spirv_to_nir_options libclc_spirv_options = { 1297ec681f3Smrg .environment = NIR_SPIRV_OPENCL, 1307ec681f3Smrg .create_library = true, 1317ec681f3Smrg .constant_addr_format = nir_address_format_32bit_index_offset_pack64, 1327ec681f3Smrg .global_addr_format = nir_address_format_32bit_index_offset_pack64, 1337ec681f3Smrg .shared_addr_format = nir_address_format_32bit_offset_as_64bit, 1347ec681f3Smrg .temp_addr_format = nir_address_format_32bit_offset_as_64bit, 1357ec681f3Smrg .float_controls_execution_mode = FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP32, 1367ec681f3Smrg .caps = { 1377ec681f3Smrg .address = true, 1387ec681f3Smrg .float64 = true, 1397ec681f3Smrg .int8 = true, 1407ec681f3Smrg .int16 = true, 1417ec681f3Smrg .int64 = true, 1427ec681f3Smrg .kernel = true, 1437ec681f3Smrg }, 1447ec681f3Smrg }; 1457ec681f3Smrg 1467ec681f3Smrg glsl_type_singleton_init_or_ref(); 1477ec681f3Smrg nir_shader *s = nir_load_libclc_shader(64, NULL, &libclc_spirv_options, options->nir_options); 1487ec681f3Smrg if (!s) { 1497ec681f3Smrg clc_error(logger, "D3D12: spirv_to_nir failed on libclc blob"); 1507ec681f3Smrg ralloc_free(ctx); 1517ec681f3Smrg return NULL; 1527ec681f3Smrg } 1537ec681f3Smrg 1547ec681f3Smrg if (options && options->optimize) 1557ec681f3Smrg clc_libclc_optimize(s); 1567ec681f3Smrg 1577ec681f3Smrg ralloc_steal(ctx, s); 1587ec681f3Smrg ctx->libclc_nir = s; 1597ec681f3Smrg 1607ec681f3Smrg return ctx; 1617ec681f3Smrg} 1627ec681f3Smrg 1637ec681f3Smrgvoid clc_free_libclc(struct clc_libclc *ctx) 1647ec681f3Smrg{ 1657ec681f3Smrg ralloc_free(ctx); 1667ec681f3Smrg glsl_type_singleton_decref(); 1677ec681f3Smrg} 1687ec681f3Smrg 1697ec681f3Smrgconst nir_shader *clc_libclc_get_clc_shader(struct clc_libclc *ctx) 1707ec681f3Smrg{ 1717ec681f3Smrg return ctx->libclc_nir; 1727ec681f3Smrg} 1737ec681f3Smrg 1747ec681f3Smrgvoid clc_libclc_serialize(struct clc_libclc *context, 1757ec681f3Smrg void **serialized, 1767ec681f3Smrg size_t *serialized_size) 1777ec681f3Smrg{ 1787ec681f3Smrg struct blob tmp; 1797ec681f3Smrg blob_init(&tmp); 1807ec681f3Smrg nir_serialize(&tmp, context->libclc_nir, true); 1817ec681f3Smrg 1827ec681f3Smrg blob_finish_get_buffer(&tmp, serialized, serialized_size); 1837ec681f3Smrg} 1847ec681f3Smrg 1857ec681f3Smrgvoid clc_libclc_free_serialized(void *serialized) 1867ec681f3Smrg{ 1877ec681f3Smrg free(serialized); 1887ec681f3Smrg} 1897ec681f3Smrg 1907ec681f3Smrgstruct clc_libclc * 1917ec681f3Smrgclc_libclc_deserialize(const void *serialized, size_t serialized_size) 1927ec681f3Smrg{ 1937ec681f3Smrg struct clc_libclc *ctx = rzalloc(NULL, struct clc_libclc); 1947ec681f3Smrg if (!ctx) { 1957ec681f3Smrg return NULL; 1967ec681f3Smrg } 1977ec681f3Smrg 1987ec681f3Smrg glsl_type_singleton_init_or_ref(); 1997ec681f3Smrg 2007ec681f3Smrg struct blob_reader tmp; 2017ec681f3Smrg blob_reader_init(&tmp, serialized, serialized_size); 2027ec681f3Smrg 2037ec681f3Smrg nir_shader *s = nir_deserialize(NULL, NULL, &tmp); 2047ec681f3Smrg if (!s) { 2057ec681f3Smrg ralloc_free(ctx); 2067ec681f3Smrg return NULL; 2077ec681f3Smrg } 2087ec681f3Smrg 2097ec681f3Smrg ralloc_steal(ctx, s); 2107ec681f3Smrg ctx->libclc_nir = s; 2117ec681f3Smrg 2127ec681f3Smrg return ctx; 2137ec681f3Smrg} 2147ec681f3Smrg 2157ec681f3Smrgbool 2167ec681f3Smrgclc_compile_c_to_spir(const struct clc_compile_args *args, 2177ec681f3Smrg const struct clc_logger *logger, 2187ec681f3Smrg struct clc_binary *out_spir) 2197ec681f3Smrg{ 2207ec681f3Smrg return clc_c_to_spir(args, logger, out_spir) >= 0; 2217ec681f3Smrg} 2227ec681f3Smrg 2237ec681f3Smrgvoid 2247ec681f3Smrgclc_free_spir(struct clc_binary *spir) 2257ec681f3Smrg{ 2267ec681f3Smrg clc_free_spir_binary(spir); 2277ec681f3Smrg} 2287ec681f3Smrg 2297ec681f3Smrgbool 2307ec681f3Smrgclc_compile_spir_to_spirv(const struct clc_binary *in_spir, 2317ec681f3Smrg const struct clc_logger *logger, 2327ec681f3Smrg struct clc_binary *out_spirv) 2337ec681f3Smrg{ 2347ec681f3Smrg if (clc_spir_to_spirv(in_spir, logger, out_spirv) < 0) 2357ec681f3Smrg return false; 2367ec681f3Smrg 2377ec681f3Smrg if (debug_get_option_debug_clc() & CLC_DEBUG_DUMP_SPIRV) 2387ec681f3Smrg clc_dump_spirv(out_spirv, stdout); 2397ec681f3Smrg 2407ec681f3Smrg return true; 2417ec681f3Smrg} 2427ec681f3Smrg 2437ec681f3Smrgvoid 2447ec681f3Smrgclc_free_spirv(struct clc_binary *spirv) 2457ec681f3Smrg{ 2467ec681f3Smrg clc_free_spirv_binary(spirv); 2477ec681f3Smrg} 2487ec681f3Smrg 2497ec681f3Smrgbool 2507ec681f3Smrgclc_compile_c_to_spirv(const struct clc_compile_args *args, 2517ec681f3Smrg const struct clc_logger *logger, 2527ec681f3Smrg struct clc_binary *out_spirv) 2537ec681f3Smrg{ 2547ec681f3Smrg if (clc_c_to_spirv(args, logger, out_spirv) < 0) 2557ec681f3Smrg return false; 2567ec681f3Smrg 2577ec681f3Smrg if (debug_get_option_debug_clc() & CLC_DEBUG_DUMP_SPIRV) 2587ec681f3Smrg clc_dump_spirv(out_spirv, stdout); 2597ec681f3Smrg 2607ec681f3Smrg return true; 2617ec681f3Smrg} 2627ec681f3Smrg 2637ec681f3Smrgbool 2647ec681f3Smrgclc_link_spirv(const struct clc_linker_args *args, 2657ec681f3Smrg const struct clc_logger *logger, 2667ec681f3Smrg struct clc_binary *out_spirv) 2677ec681f3Smrg{ 2687ec681f3Smrg if (clc_link_spirv_binaries(args, logger, out_spirv) < 0) 2697ec681f3Smrg return false; 2707ec681f3Smrg 2717ec681f3Smrg if (debug_get_option_debug_clc() & CLC_DEBUG_DUMP_SPIRV) 2727ec681f3Smrg clc_dump_spirv(out_spirv, stdout); 2737ec681f3Smrg 2747ec681f3Smrg return true; 2757ec681f3Smrg} 2767ec681f3Smrg 2777ec681f3Smrgbool 2787ec681f3Smrgclc_parse_spirv(const struct clc_binary *in_spirv, 2797ec681f3Smrg const struct clc_logger *logger, 2807ec681f3Smrg struct clc_parsed_spirv *out_data) 2817ec681f3Smrg{ 2827ec681f3Smrg if (!clc_spirv_get_kernels_info(in_spirv, 2837ec681f3Smrg &out_data->kernels, 2847ec681f3Smrg &out_data->num_kernels, 2857ec681f3Smrg &out_data->spec_constants, 2867ec681f3Smrg &out_data->num_spec_constants, 2877ec681f3Smrg logger)) 2887ec681f3Smrg return false; 2897ec681f3Smrg 2907ec681f3Smrg if (debug_get_option_debug_clc() & CLC_DEBUG_VERBOSE) 2917ec681f3Smrg clc_print_kernels_info(out_data); 2927ec681f3Smrg 2937ec681f3Smrg return true; 2947ec681f3Smrg} 2957ec681f3Smrg 2967ec681f3Smrgvoid clc_free_parsed_spirv(struct clc_parsed_spirv *data) 2977ec681f3Smrg{ 2987ec681f3Smrg clc_free_kernels_info(data->kernels, data->num_kernels); 2997ec681f3Smrg} 3007ec681f3Smrg 3017ec681f3Smrgbool 3027ec681f3Smrgclc_specialize_spirv(const struct clc_binary *in_spirv, 3037ec681f3Smrg const struct clc_parsed_spirv *parsed_data, 3047ec681f3Smrg const struct clc_spirv_specialization_consts *consts, 3057ec681f3Smrg struct clc_binary *out_spirv) 3067ec681f3Smrg{ 3077ec681f3Smrg if (!clc_spirv_specialize(in_spirv, parsed_data, consts, out_spirv)) 3087ec681f3Smrg return false; 3097ec681f3Smrg 3107ec681f3Smrg if (debug_get_option_debug_clc() & CLC_DEBUG_DUMP_SPIRV) 3117ec681f3Smrg clc_dump_spirv(out_spirv, stdout); 3127ec681f3Smrg 3137ec681f3Smrg return true; 3147ec681f3Smrg} 315