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