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