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