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