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, ¶ms->devinfo);
420
421 struct brw_compiler *compiler = brw_compiler_create(params->mem_ctx,
422 ¶ms->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(¶ms, &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, ¶ms.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(¶ms, &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