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