• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2021 Intel 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 "brw_compiler.h"
25 #include "brw_kernel.h"
26 #include "compiler/brw_disasm.h"
27 #include "compiler/clc/clc.h"
28 #include "compiler/glsl_types.h"
29 #include "compiler/nir/nir_serialize.h"
30 #include "dev/intel_debug.h"
31 #include "util/build_id.h"
32 #include "util/disk_cache.h"
33 #include "util/macros.h"
34 #include "util/mesa-sha1.h"
35 #include "util/u_dynarray.h"
36 
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <getopt.h>
40 #include <inttypes.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <sys/mman.h>
44 
45 /* Shader functions */
46 #define SPIR_V_MAGIC_NUMBER 0x07230203
47 
48 static struct disk_cache *
get_disk_cache(struct brw_compiler * compiler)49 get_disk_cache(struct brw_compiler *compiler)
50 {
51 #ifdef ENABLE_SHADER_CACHE
52    char renderer[14];
53    ASSERTED int len = snprintf(renderer, sizeof(renderer), "brw_clc_%04x",
54                                compiler->devinfo->pci_device_id);
55    assert(len == sizeof(renderer) - 2);
56 
57    const struct build_id_note *note =
58       build_id_find_nhdr_for_addr(get_disk_cache);
59    if (note == NULL) {
60       fprintf(stderr, "Failed to find build-id\n");
61       abort();
62    }
63 
64    unsigned build_id_len = build_id_length(note);
65    if (build_id_len < 20) {
66       fprintf(stderr, "build-id too short.  It needs to be a SHA\n");
67       abort();
68    }
69 
70    struct mesa_sha1 sha1_ctx;
71    uint8_t sha1[20];
72    _mesa_sha1_init(&sha1_ctx);
73    _mesa_sha1_update(&sha1_ctx, build_id_data(note), build_id_len);
74    _mesa_sha1_final(&sha1_ctx, sha1);
75 
76    char timestamp[41];
77    _mesa_sha1_format(timestamp, sha1);
78 
79    const uint64_t driver_flags = brw_get_compiler_config_value(compiler);
80 
81    return disk_cache_create(renderer, timestamp, driver_flags);
82 #endif
83    return NULL;
84 }
85 
86 static void
compiler_log(void * data,unsigned * id,const char * fmt,...)87 compiler_log(void *data, unsigned *id, const char *fmt, ...)
88 {
89    va_list args;
90    va_start(args, fmt);
91    if (INTEL_DEBUG(DEBUG_CS))
92       vfprintf(stderr, fmt, args);
93    va_end(args);
94 }
95 
96 static void
msg_callback(void * priv,const char * msg)97 msg_callback(void *priv, const char *msg)
98 {
99    (void)priv;
100    fprintf(stderr, "%s", msg);
101 }
102 
103 static void
print_u32_data(FILE * fp,const char * prefix,const char * arr_name,const uint32_t * data,size_t len)104 print_u32_data(FILE *fp, const char *prefix, const char *arr_name,
105                const uint32_t *data, size_t len)
106 {
107    assert(len % 4 == 0);
108    fprintf(fp, "static const uint32_t %s_%s[] = {", prefix, arr_name);
109    for (unsigned i = 0; i < (len / 4); i++) {
110       if (i % 4 == 0)
111          fprintf(fp,"\n   ");
112 
113       fprintf(fp, " 0x%08" PRIx32 ",", data[i]);
114    }
115    fprintf(fp, "\n};\n");
116 }
117 
118 static void
print_u8_data(FILE * fp,const char * prefix,const char * arr_name,const uint8_t * data,size_t len)119 print_u8_data(FILE *fp, const char *prefix, const char *arr_name,
120                const uint8_t *data, size_t len)
121 {
122    fprintf(fp, "static const uint8_t %s_%s[] = {", prefix, arr_name);
123    for (unsigned i = 0; i < len; i++) {
124       if (i % 16 == 0)
125          fprintf(fp,"\n   ");
126 
127       fprintf(fp, " 0x%02" PRIx8 ",", data[i]);
128    }
129    fprintf(fp, "\n};\n");
130 }
131 
132 static const char *
reloc_type_str(enum brw_shader_reloc_type type)133 reloc_type_str(enum brw_shader_reloc_type type)
134 {
135    switch (type) {
136 #define CASE(e) case e: return #e;
137    CASE(BRW_SHADER_RELOC_TYPE_U32)
138    CASE(BRW_SHADER_RELOC_TYPE_MOV_IMM)
139 #undef CASE
140    default:
141       unreachable("Unknown relocation type");
142    }
143 }
144 
145 static void
print_cs_prog_data_fields(FILE * fp,const char * prefix,const char * pad,const struct brw_cs_prog_data * cs_prog_data)146 print_cs_prog_data_fields(FILE *fp, const char *prefix, const char *pad,
147                           const struct brw_cs_prog_data *cs_prog_data)
148 {
149 #define PROG_DATA_FIELD(fmt, field) \
150    fprintf(fp, "%s." #field " = " fmt ",\n", pad, cs_prog_data->field)
151 
152 #define PROG_DATA_BOOL_FIELD(field) \
153    fprintf(fp, "%s." #field " = %s,\n", pad, \
154            cs_prog_data->field ? "true" : "false")
155 
156    PROG_DATA_FIELD("%u", base.nr_params);
157    assert(cs_prog_data->base.stage == MESA_SHADER_COMPUTE);
158    fprintf(fp, "%s.base.stage = MESA_SHADER_COMPUTE,\n", pad);
159    assert(cs_prog_data->base.zero_push_reg == 0);
160    assert(cs_prog_data->base.push_reg_mask_param == 0);
161    PROG_DATA_FIELD("%u", base.curb_read_length);
162    PROG_DATA_FIELD("%u", base.total_scratch);
163    PROG_DATA_FIELD("%u", base.total_shared);
164    PROG_DATA_FIELD("%u", base.program_size);
165    PROG_DATA_FIELD("%u", base.const_data_size);
166    PROG_DATA_FIELD("%u", base.const_data_offset);
167    PROG_DATA_FIELD("%u", base.num_relocs);
168    fprintf(fp, "%s.base.relocs = %s_relocs,\n", pad, prefix);
169    assert(!cs_prog_data->base.has_ubo_pull);
170    assert(cs_prog_data->base.dispatch_grf_start_reg == 0);
171    assert(!cs_prog_data->base.use_alt_mode);
172    assert(cs_prog_data->base.param == 0);
173    PROG_DATA_BOOL_FIELD(base.uses_atomic_load_store);
174    fprintf(fp, "%s.local_size = { %u, %u, %u },\n", pad,
175            cs_prog_data->local_size[0],
176            cs_prog_data->local_size[1],
177            cs_prog_data->local_size[2]);
178    fprintf(fp, "%s.prog_offset = { %u, %u, %u },\n", pad,
179            cs_prog_data->prog_offset[0],
180            cs_prog_data->prog_offset[1],
181            cs_prog_data->prog_offset[2]);
182    PROG_DATA_FIELD("%u", prog_mask);
183    PROG_DATA_FIELD("%u", prog_spilled);
184    PROG_DATA_BOOL_FIELD(uses_barrier);
185    PROG_DATA_BOOL_FIELD(uses_num_work_groups);
186    assert(!cs_prog_data->uses_inline_data);
187    assert(!cs_prog_data->uses_btd_stack_ids);
188    PROG_DATA_FIELD("%u", push.per_thread.dwords);
189    PROG_DATA_FIELD("%u", push.per_thread.regs);
190    PROG_DATA_FIELD("%u", push.per_thread.size);
191    PROG_DATA_FIELD("%u", push.cross_thread.dwords);
192    PROG_DATA_FIELD("%u", push.cross_thread.regs);
193    PROG_DATA_FIELD("%u", push.cross_thread.size);
194 
195 #undef PROG_DATA_FIELD
196 #undef PROG_DATA_BOOL_FIELD
197 }
198 
199 static void
print_kernel(FILE * fp,const char * prefix,const struct brw_kernel * kernel,const struct brw_isa_info * isa)200 print_kernel(FILE *fp, const char *prefix,
201              const struct brw_kernel *kernel,
202              const struct brw_isa_info *isa)
203 {
204    struct mesa_sha1 sha1_ctx;
205    _mesa_sha1_init(&sha1_ctx);
206 
207 #define SHA1_UPDATE_VALUE(val) \
208    _mesa_sha1_update(&sha1_ctx, &val, sizeof(val))
209 
210    fprintf(fp, "#include \"intel/compiler/brw_kernel.h\"\n");
211    fprintf(fp, "\n");
212 
213    fprintf(fp, "static const struct brw_shader_reloc %s_relocs[] = {\n",
214            prefix);
215    for (unsigned i = 0; i < kernel->prog_data.base.num_relocs; i++) {
216       const struct brw_shader_reloc *reloc = &kernel->prog_data.base.relocs[i];
217       fprintf(fp, "   { %"PRIu32", %s, %"PRIu32", %"PRIu32" },\n",
218               reloc->id, reloc_type_str(reloc->type),
219               reloc->offset, reloc->delta);
220    }
221    fprintf(fp, "};\n");
222    _mesa_sha1_update(&sha1_ctx, kernel->prog_data.base.relocs,
223                      kernel->prog_data.base.num_relocs *
224                      sizeof(kernel->prog_data.base.relocs[0]));
225 
226    /* Get rid of the pointers before we hash */
227    struct brw_cs_prog_data cs_prog_data = kernel->prog_data;
228    cs_prog_data.base.relocs = NULL;
229    assert(cs_prog_data.base.param == NULL);
230    _mesa_sha1_update(&sha1_ctx, &cs_prog_data, sizeof(cs_prog_data));
231 
232    SHA1_UPDATE_VALUE(kernel->args_size);
233    SHA1_UPDATE_VALUE(kernel->arg_count);
234    _mesa_sha1_update(&sha1_ctx, kernel->args,
235                      kernel->arg_count * sizeof(kernel->args[0]));
236 
237    fprintf(fp, "static const struct brw_kernel_arg_desc %s_args[] = {\n",
238            prefix);
239    for (unsigned i = 0; i < kernel->arg_count; i++) {
240       fprintf(fp, "   { %d, %d },\n",
241               kernel->args[i].offset, kernel->args[i].size);
242    }
243    fprintf(fp, "};\n\n");
244 
245    _mesa_sha1_update(&sha1_ctx, kernel->code,
246                      kernel->prog_data.base.program_size);
247 
248    fprintf(fp, "#if 0  /* BEGIN KERNEL ASSEMBLY */\n");
249    fprintf(fp, "\n");
250    brw_disassemble_with_errors(isa, kernel->code, 0, fp);
251    fprintf(fp, "\n");
252    fprintf(fp, "#endif /* END KERNEL ASSEMBLY */\n");
253    print_u32_data(fp, prefix, "code", kernel->code,
254                   kernel->prog_data.base.program_size);
255 
256    fprintf(fp, "static const struct brw_kernel %s = {\n", prefix);
257    fprintf(fp, "   .prog_data = {\n");
258    print_cs_prog_data_fields(fp, prefix, "      ", &kernel->prog_data);
259    fprintf(fp, "   },\n");
260    fprintf(fp, "   .args_size = %d,\n", (int)kernel->args_size);
261    fprintf(fp, "   .arg_count = %d,\n", (int)kernel->arg_count);
262    fprintf(fp, "   .args = %s_args,\n", prefix);
263    fprintf(fp, "   .code = %s_code,\n", prefix);
264    fprintf(fp, "};\n");
265 
266    unsigned char sha1[20];
267    _mesa_sha1_final(&sha1_ctx, sha1);
268    char sha1_str[41];
269    _mesa_sha1_format(sha1_str, sha1);
270    fprintf(fp, "const char *%s_sha1 = \"%s\";\n", prefix, sha1_str);
271 }
272 
273 static void
print_usage(char * exec_name,FILE * f)274 print_usage(char *exec_name, FILE *f)
275 {
276    fprintf(f,
277 "Usage: %s [options] -- [clang args]\n"
278 "Options:\n"
279 "  -h  --help              Print this help.\n"
280 "  -e, --entrypoint <name> Specify the entry-point name.\n"
281 "  -L, --llvm17-wa         Enable LLVM 17 workarounds for opaque pointers"
282 "  -p, --platform <name>   Specify the target platform name.\n"
283 "      --prefix <prefix>   Prefix for variable names in generated C code.\n"
284 "  -o, --out <filename>    Specify the output filename.\n"
285 "  -i, --in <filename>     Specify one input filename. Accepted multiple times.\n"
286 "  -s, --spv <filename>    Specify the output filename for spirv.\n"
287 "  -n, --nir               Specify whether to output serialized NIR instead of ISA.\n"
288 "  -g, --gfx-version <ver> Specify the Gfx version used for NIR output.\n"
289 "  -t, --text <filename>   Specify the output filename for the parsed text\n"
290 "  -v, --verbose           Print more information during compilation.\n"
291 "  -M, --llvm-version      Print LLVM version.\n"
292    , exec_name);
293 }
294 
295 #define OPT_PREFIX 1000
296 
297 struct intel_clc_params {
298    char *entry_point;
299    char *platform;
300    char *outfile;
301    char *spv_outfile;
302    char *txt_outfile;
303    char *prefix;
304 
305    unsigned gfx_version;
306 
307    bool output_nir;
308    bool print_info;
309    bool llvm17_wa;
310 
311    void *mem_ctx;
312 
313    struct intel_device_info devinfo;
314 };
315 
316 #include "compiler/spirv/nir_spirv.h"
317 
318 static int
output_nir(const struct intel_clc_params * params,struct clc_binary * binary)319 output_nir(const struct intel_clc_params *params, struct clc_binary *binary)
320 {
321    struct spirv_to_nir_options spirv_options = {
322       .environment = NIR_SPIRV_OPENCL,
323       .caps = {
324          .address = true,
325          .groups = true,
326          .image_write_without_format = true,
327          .int8 = true,
328          .int16 = true,
329          .int64 = true,
330          .int64_atomics = true,
331          .kernel = true,
332          .linkage = true, /* We receive linked kernel from clc */
333          .float_controls = true,
334          .generic_pointers = true,
335          .storage_8bit = true,
336          .storage_16bit = true,
337          .subgroup_arithmetic = true,
338          .subgroup_basic = true,
339          .subgroup_ballot = true,
340          .subgroup_dispatch = true,
341          .subgroup_quad = true,
342          .subgroup_shuffle = true,
343          .subgroup_vote = true,
344 
345          .intel_subgroup_shuffle = true,
346          .intel_subgroup_buffer_block_io = true,
347       },
348       .shared_addr_format = nir_address_format_62bit_generic,
349       .global_addr_format = nir_address_format_62bit_generic,
350       .temp_addr_format = nir_address_format_62bit_generic,
351       .constant_addr_format = nir_address_format_64bit_global,
352       .create_library = true,
353    };
354 
355    FILE *fp = params->outfile != NULL ?
356       fopen(params->outfile, "w") : stdout;
357    if (!fp) {
358       fprintf(stderr, "Failed to open %s\n", params->outfile);
359       return -1;
360    }
361 
362    spirv_library_to_nir_builder(fp, binary->data, binary->size / 4,
363                                 &spirv_options);
364 
365    nir_shader *nir = brw_nir_from_spirv(params->mem_ctx, params->gfx_version,
366                                         binary->data, binary->size,
367                                         params->llvm17_wa);
368    if (!nir) {
369       fprintf(stderr, "Failed to generate NIR out of SPIRV\n");
370       fclose(fp);
371       return -1;
372    }
373 
374    struct blob blob;
375    blob_init(&blob);
376    nir_serialize(&blob, nir, false /* strip */);
377    print_u8_data(fp, params->prefix, "nir", blob.data, blob.size);
378    blob_finish(&blob);
379 
380    if (params->outfile)
381       fclose(fp);
382 
383    return 0;
384 }
385 
386 static int
output_isa(const struct intel_clc_params * params,struct clc_binary * binary)387 output_isa(const struct intel_clc_params *params, struct clc_binary *binary)
388 {
389    struct brw_kernel kernel = {};
390    char *error_str;
391 
392    struct brw_isa_info _isa, *isa = &_isa;
393    brw_init_isa_info(isa, &params->devinfo);
394 
395    struct brw_compiler *compiler = brw_compiler_create(params->mem_ctx,
396                                                        &params->devinfo);
397    compiler->shader_debug_log = compiler_log;
398    compiler->shader_perf_log = compiler_log;
399    struct disk_cache *disk_cache = get_disk_cache(compiler);
400 
401    if (!brw_kernel_from_spirv(compiler, disk_cache, &kernel, NULL, params->mem_ctx,
402                               binary->data, binary->size,
403                               params->entry_point, &error_str)) {
404       fprintf(stderr, "Compile failed: %s\n", error_str);
405       return -1;
406    }
407 
408    if (params->print_info) {
409       fprintf(stdout, "kernel info:\n");
410       fprintf(stdout, "   uses_barrier           : %u\n", kernel.prog_data.uses_barrier);
411       fprintf(stdout, "   uses_num_work_groups   : %u\n", kernel.prog_data.uses_num_work_groups);
412       fprintf(stdout, "   uses_inline_data       : %u\n", kernel.prog_data.uses_inline_data);
413       fprintf(stdout, "   local_size             : %ux%ux%u\n",
414               kernel.prog_data.local_size[0],
415               kernel.prog_data.local_size[1],
416               kernel.prog_data.local_size[2]);
417       fprintf(stdout, "   curb_read_length       : %u\n", kernel.prog_data.base.curb_read_length);
418       fprintf(stdout, "   total_scratch          : %u\n", kernel.prog_data.base.total_scratch);
419       fprintf(stdout, "   total_shared           : %u\n", kernel.prog_data.base.total_shared);
420       fprintf(stdout, "   program_size           : %u\n", kernel.prog_data.base.program_size);
421       fprintf(stdout, "   const_data_size        : %u\n", kernel.prog_data.base.const_data_size);
422       fprintf(stdout, "   uses_atomic_load_store : %u\n", kernel.prog_data.base.uses_atomic_load_store);
423       fprintf(stdout, "   dispatch_grf_start_reg : %u\n", kernel.prog_data.base.dispatch_grf_start_reg);
424    }
425 
426    char *prefix = params->prefix;
427    char prefix_tmp[256];
428    if (prefix == NULL) {
429       bool is_pt_5 = (params->devinfo.verx10 % 10) == 5;
430       snprintf(prefix_tmp, sizeof(prefix_tmp), "gfx%d%s_clc_%s",
431                params->devinfo.ver, is_pt_5 ? "5" : "", params->entry_point);
432       prefix = prefix_tmp;
433    }
434 
435    if (params->outfile != NULL) {
436       FILE *fp = fopen(params->outfile, "w");
437       print_kernel(fp, prefix, &kernel, isa);
438       fclose(fp);
439    } else {
440       print_kernel(stdout, prefix, &kernel, isa);
441    }
442 
443    return 0;
444 }
445 
446 static void
print_llvm_version(FILE * out)447 print_llvm_version(FILE *out)
448 {
449    fprintf(out, "%s\n", MESA_LLVM_VERSION_STRING);
450 }
451 
main(int argc,char ** argv)452 int main(int argc, char **argv)
453 {
454    int exit_code = 0;
455 
456    process_intel_debug_variable();
457 
458    static struct option long_options[] ={
459       {"help",         no_argument,         0, 'h'},
460       {"entrypoint",   required_argument,   0, 'e'},
461       {"platform",     required_argument,   0, 'p'},
462       {"prefix",       required_argument,   0, OPT_PREFIX},
463       {"in",           required_argument,   0, 'i'},
464       {"out",          required_argument,   0, 'o'},
465       {"spv",          required_argument,   0, 's'},
466       {"text",         required_argument,   0, 't'},
467       {"gfx-version",  required_argument,   0, 'g'},
468       {"nir",          no_argument,         0, 'n'},
469       {"llvm17-wa",    no_argument,         0, 'L'},
470       {"llvm-version", no_argument,         0, 'M'},
471       {"verbose",      no_argument,         0, 'v'},
472       {0, 0, 0, 0}
473    };
474 
475    struct intel_clc_params params = {};
476 
477    struct util_dynarray clang_args;
478    struct util_dynarray input_files;
479 
480    struct clc_binary spirv_obj = {0};
481    struct clc_parsed_spirv parsed_spirv_data = {0};
482    struct disk_cache *disk_cache = NULL;
483 
484    params.mem_ctx = ralloc_context(NULL);
485 
486    util_dynarray_init(&clang_args, params.mem_ctx);
487    util_dynarray_init(&input_files, params.mem_ctx);
488 
489    int ch;
490    while ((ch = getopt_long(argc, argv, "he:p:s:t:i:no:MLvg:", long_options, NULL)) != -1)
491    {
492       switch (ch)
493       {
494       case 'h':
495          print_usage(argv[0], stdout);
496          goto end;
497       case 'e':
498          params.entry_point = optarg;
499          break;
500       case 'p':
501          params.platform = optarg;
502          break;
503       case 'o':
504          params.outfile = optarg;
505          break;
506       case 'i':
507          util_dynarray_append(&input_files, char *, optarg);
508 	 break;
509       case 'n':
510          params.output_nir = true;
511          break;
512       case 's':
513          params.spv_outfile = optarg;
514          break;
515       case 't':
516          params.txt_outfile = optarg;
517          break;
518       case 'v':
519          params.print_info = true;
520          break;
521       case 'L':
522          params.llvm17_wa = true;
523          break;
524       case 'M':
525          print_llvm_version(stdout);
526          return EXIT_SUCCESS;
527       case 'g':
528          params.gfx_version = strtoul(optarg, NULL, 10);
529          break;
530       case OPT_PREFIX:
531          params.prefix = optarg;
532          break;
533       default:
534          fprintf(stderr, "Unrecognized option \"%s\".\n", optarg);
535          print_usage(argv[0], stderr);
536          goto fail;
537       }
538    }
539 
540    for (int i = optind; i < argc; i++) {
541       util_dynarray_append(&clang_args, char *, argv[i]);
542    }
543 
544    if (util_dynarray_num_elements(&input_files, char *) == 0) {
545       fprintf(stderr, "No input file(s).\n");
546       print_usage(argv[0], stderr);
547       goto fail;
548    }
549 
550    struct clc_logger logger = {
551       .error = msg_callback,
552       .warning = msg_callback,
553    };
554 
555    size_t total_size = 0;
556    char *all_inputs = NULL;
557    util_dynarray_foreach(&input_files, char *, infile) {
558       int fd = open(*infile, O_RDONLY);
559       if (fd < 0) {
560          fprintf(stderr, "Failed to open %s\n", *infile);
561          goto fail;
562       }
563 
564       off_t len = lseek(fd, 0, SEEK_END);
565       size_t new_size = total_size + len;
566       all_inputs = reralloc_size(params.mem_ctx, all_inputs, new_size + 1);
567       if (!all_inputs) {
568          fprintf(stderr, "Failed to allocate memory\n");
569          goto fail;
570       }
571       lseek(fd, 0, SEEK_SET);
572       read(fd, all_inputs + total_size, len);
573       close(fd);
574       total_size = new_size;
575       all_inputs[total_size] = '\0';
576    }
577 
578    if (params.txt_outfile) {
579       FILE *fp = fopen(params.txt_outfile, "w");
580       fwrite(all_inputs, total_size, 1, fp);
581       fclose(fp);
582    }
583 
584    const char *allowed_spirv_extensions[] = {
585       "SPV_EXT_shader_atomic_float_add",
586       "SPV_EXT_shader_atomic_float_min_max",
587       "SPV_KHR_float_controls",
588       "SPV_INTEL_subgroups",
589       NULL,
590    };
591 
592    struct clc_compile_args clc_args = {
593       .source = {
594          .name = "intel_clc_files",
595          .value = all_inputs,
596       },
597       .features = {
598          .fp16 = true,
599          .intel_subgroups = true,
600          .subgroups = true,
601          .subgroups_ifp = true,
602       },
603       .args = util_dynarray_begin(&clang_args),
604       .num_args = util_dynarray_num_elements(&clang_args, char *),
605       .allowed_spirv_extensions = allowed_spirv_extensions,
606    };
607 
608    if (!clc_compile_c_to_spirv(&clc_args, &logger, &spirv_obj)) {
609       goto fail;
610    }
611 
612    if (params.spv_outfile) {
613       FILE *fp = fopen(params.spv_outfile, "w");
614       fwrite(spirv_obj.data, spirv_obj.size, 1, fp);
615       fclose(fp);
616    }
617 
618    glsl_type_singleton_init_or_ref();
619 
620    if (params.output_nir) {
621       if (params.gfx_version == 0) {
622          fprintf(stderr, "No target Gfx version specified.\n");
623          print_usage(argv[0], stderr);
624          goto fail;
625       }
626 
627       exit_code = output_nir(&params, &spirv_obj);
628    } else {
629       if (params.platform == NULL) {
630          fprintf(stderr, "No target platform name specified.\n");
631          print_usage(argv[0], stderr);
632          goto fail;
633       }
634 
635       int pci_id = intel_device_name_to_pci_device_id(params.platform);
636       if (pci_id < 0) {
637          fprintf(stderr, "Invalid target platform name: %s\n", params.platform);
638          goto fail;
639       }
640 
641       if (!intel_get_device_info_from_pci_id(pci_id, &params.devinfo)) {
642          fprintf(stderr, "Failed to get device information.\n");
643          goto fail;
644       }
645 
646       if (params.devinfo.verx10 < 125) {
647          fprintf(stderr, "Platform currently not supported.\n");
648          goto fail;
649       }
650 
651       if (params.gfx_version) {
652          fprintf(stderr, "WARNING: Ignorining unnecessary parameter for "
653                          "gfx version, using version based on platform.\n");
654          /* Keep going. */
655       }
656 
657       if (params.entry_point == NULL) {
658          fprintf(stderr, "No entry-point name specified.\n");
659          print_usage(argv[0], stderr);
660          goto fail;
661       }
662 
663       struct clc_parsed_spirv parsed_spirv_data;
664       if (!clc_parse_spirv(&spirv_obj, &logger, &parsed_spirv_data))
665          goto fail;
666 
667       const struct clc_kernel_info *kernel_info = NULL;
668       for (unsigned i = 0; i < parsed_spirv_data.num_kernels; i++) {
669          if (strcmp(parsed_spirv_data.kernels[i].name, params.entry_point) == 0) {
670             kernel_info = &parsed_spirv_data.kernels[i];
671             break;
672          }
673       }
674       if (kernel_info == NULL) {
675          fprintf(stderr, "Kernel entrypoint %s not found\n", params.entry_point);
676          goto fail;
677       }
678 
679       exit_code = output_isa(&params, &spirv_obj);
680    }
681 
682    glsl_type_singleton_decref();
683 
684    goto end;
685 
686 fail:
687    exit_code = 1;
688 
689 end:
690    disk_cache_destroy(disk_cache);
691    clc_free_parsed_spirv(&parsed_spirv_data);
692    clc_free_spirv(&spirv_obj);
693    ralloc_free(params.mem_ctx);
694 
695    return exit_code;
696 }
697