xref: /aosp_15_r20/external/igt-gpu-tools/assembler/main.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /* -*- c-basic-offset: 8 -*- */
2 /*
3  * Copyright © 2006 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * Authors:
25  *    Eric Anholt <[email protected]>
26  *
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <getopt.h>
33 #include <unistd.h>
34 #include <assert.h>
35 
36 #include "ralloc.h"
37 #include "gen4asm.h"
38 #include "brw_eu.h"
39 
40 extern FILE *yyin;
41 extern void set_branch_two_offsets(struct brw_program_instruction *insn, int jip_offset, int uip_offset);
42 extern void set_branch_one_offset(struct brw_program_instruction *insn, int jip_offset);
43 
44 long int gen_level = 40;
45 int advanced_flag = 0; /* 0: in unit of byte, 1: in unit of data element size */
46 unsigned int warning_flags = WARN_ALWAYS;
47 int need_export = 0;
48 char *input_filename = "<stdin>";
49 int errors;
50 
51 struct brw_context genasm_brw_context;
52 struct brw_compile genasm_compile;
53 
54 struct brw_program compiled_program;
55 struct program_defaults program_defaults = {.register_type = BRW_REGISTER_TYPE_F};
56 
57 /* 0: default output style, 1: nice C-style output */
58 static int binary_like_output = 0;
59 static char *export_filename = NULL;
60 static const char binary_prepend[] = "static const char gen_eu_bytes[] = {\n";
61 
62 #define HASH_SIZE 37
63 
64 struct hash_item {
65 	char *key;
66 	void *value;
67 	struct hash_item *next;
68 };
69 
70 typedef struct hash_item *hash_table[HASH_SIZE];
71 
72 static hash_table declared_register_table;
73 
74 struct label_item {
75 	char *name;
76 	int addr;
77 	struct label_item *next;
78 };
79 static struct label_item *label_table;
80 
81 static const struct option longopts[] = {
82 	{"advanced", no_argument, 0, 'a'},
83 	{"binary", no_argument, 0, 'b'},
84 	{"export", required_argument, 0, 'e'},
85 	{"input_list", required_argument, 0, 'l'},
86 	{"output", required_argument, 0, 'o'},
87 	{"gen", required_argument, 0, 'g'},
88 	{ NULL, 0, NULL, 0 }
89 };
90 
usage(void)91 static void usage(void)
92 {
93 	fprintf(stderr, "usage: intel-gen4asm [options] inputfile\n");
94 	fprintf(stderr, "OPTIONS:\n");
95 	fprintf(stderr, "\t-a, --advanced                       Set advanced flag\n");
96 	fprintf(stderr, "\t-b, --binary                         C style binary output\n");
97 	fprintf(stderr, "\t-e, --export {exportfile}            Export label file\n");
98 	fprintf(stderr, "\t-l, --input_list {entrytablefile}    Input entry_table_list file\n");
99 	fprintf(stderr, "\t-o, --output {outputfile}            Specify output file\n");
100 	fprintf(stderr, "\t-g, --gen <4|5|6|7|8|9>              Specify GPU generation\n");
101 }
102 
hash(char * key)103 static int hash(char *key)
104 {
105     unsigned ret = 0;
106     while(*key)
107         ret = (ret << 1) + (*key++);
108     return ret % HASH_SIZE;
109 }
110 
find_hash_item(hash_table t,char * key)111 static void *find_hash_item(hash_table t, char *key)
112 {
113     struct hash_item *p;
114     for(p = t[hash(key)]; p; p = p->next)
115 	if(strcasecmp(p->key, key) == 0)
116 	    return p->value;
117     return NULL;
118 }
119 
insert_hash_item(hash_table t,char * key,void * v)120 static void insert_hash_item(hash_table t, char *key, void *v)
121 {
122     int index = hash(key);
123     struct hash_item *p = malloc(sizeof(*p));
124     p->key = key;
125     p->value = v;
126     p->next = t[index];
127     t[index] = p;
128 }
129 
free_hash_table(hash_table t)130 static void free_hash_table(hash_table t)
131 {
132     struct hash_item *p, *next;
133     int i;
134     for (i = 0; i < HASH_SIZE; i++) {
135 	p = t[i];
136 	while(p) {
137 	    next = p->next;
138 	    free(p->key);
139 	    free(p->value);
140 	    free(p);
141 	    p = next;
142 	}
143     }
144 }
145 
find_register(char * name)146 struct declared_register *find_register(char *name)
147 {
148     return find_hash_item(declared_register_table, name);
149 }
150 
insert_register(struct declared_register * reg)151 void insert_register(struct declared_register *reg)
152 {
153     insert_hash_item(declared_register_table, reg->name, reg);
154 }
155 
add_label(struct brw_program_instruction * i)156 static void add_label(struct brw_program_instruction *i)
157 {
158     struct label_item **p = &label_table;
159 
160     assert(is_label(i));
161 
162     while(*p)
163         p = &((*p)->next);
164     *p = calloc(1, sizeof(**p));
165     (*p)->name = label_name(i);
166     (*p)->addr = i->inst_offset;
167 }
168 
169 /* Some assembly code have duplicated labels.
170    Start from start_addr. Search as a loop. Return the first label found. */
label_to_addr(char * name,int start_addr)171 static int label_to_addr(char *name, int start_addr)
172 {
173     /* return the first label just after start_addr, or the first label from the head */
174     struct label_item *p;
175     int r = -1;
176     for(p = label_table; p; p = p->next) {
177         if(strcmp(p->name, name) == 0) {
178             if(p->addr >= start_addr) // the first label just after start_addr
179                 return p->addr;
180             else if(r == -1) // the first label from the head
181                 r = p->addr;
182         }
183     }
184     if(r == -1) {
185         fprintf(stderr, "Can't find label %s\n", name);
186         exit(1);
187     }
188     return r;
189 }
190 
free_label_table(struct label_item * p)191 static void free_label_table(struct label_item *p)
192 {
193     if(p) {
194         free_label_table(p->next);
195         free(p);
196     }
197 }
198 
199 struct entry_point_item {
200 	char *str;
201 	struct entry_point_item *next;
202 } *entry_point_table;
203 
read_entry_file(char * fn)204 static int read_entry_file(char *fn)
205 {
206 	FILE *entry_table_file;
207 	char buf[2048];
208 	struct entry_point_item **p = &entry_point_table;
209 	if (!fn)
210 		return 0;
211 	if ((entry_table_file = fopen(fn, "r")) == NULL)
212 		return -1;
213 	while (fgets(buf, sizeof(buf)-1, entry_table_file) != NULL) {
214 		// drop the final char '\n'
215 		if(buf[strlen(buf)-1] == '\n')
216 			buf[strlen(buf)-1] = 0;
217 		*p = calloc(1, sizeof(struct entry_point_item));
218 		(*p)->str = strdup(buf);
219 		p = &((*p)->next);
220 	}
221 	fclose(entry_table_file);
222 	return 0;
223 }
224 
is_entry_point(struct brw_program_instruction * i)225 static int is_entry_point(struct brw_program_instruction *i)
226 {
227 	struct entry_point_item *p;
228 
229 	assert(i->type == GEN4ASM_INSTRUCTION_LABEL);
230 
231 	for (p = entry_point_table; p; p = p->next) {
232 	    if (strcmp(p->str, i->insn.label.name) == 0)
233 		return 1;
234 	}
235 	return 0;
236 }
237 
free_entry_point_table(struct entry_point_item * p)238 static void free_entry_point_table(struct entry_point_item *p) {
239 	if (p) {
240 		free_entry_point_table(p->next);
241 		free(p->str);
242 		free(p);
243 	}
244 }
245 
246 static void
print_instruction(FILE * output,struct brw_instruction * instruction)247 print_instruction(FILE *output, struct brw_instruction *instruction)
248 {
249 	if (binary_like_output) {
250 		fprintf(output, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x, "
251 				"0x%02x, 0x%02x, 0x%02x, 0x%02x,\n"
252 				"\t0x%02x, 0x%02x, 0x%02x, 0x%02x, "
253 				"0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
254 			((unsigned char *)instruction)[0],
255 			((unsigned char *)instruction)[1],
256 			((unsigned char *)instruction)[2],
257 			((unsigned char *)instruction)[3],
258 			((unsigned char *)instruction)[4],
259 			((unsigned char *)instruction)[5],
260 			((unsigned char *)instruction)[6],
261 			((unsigned char *)instruction)[7],
262 			((unsigned char *)instruction)[8],
263 			((unsigned char *)instruction)[9],
264 			((unsigned char *)instruction)[10],
265 			((unsigned char *)instruction)[11],
266 			((unsigned char *)instruction)[12],
267 			((unsigned char *)instruction)[13],
268 			((unsigned char *)instruction)[14],
269 			((unsigned char *)instruction)[15]);
270 	} else {
271 		fprintf(output, "   { 0x%08x, 0x%08x, 0x%08x, 0x%08x },\n",
272 			((int *)instruction)[0],
273 			((int *)instruction)[1],
274 			((int *)instruction)[2],
275 			((int *)instruction)[3]);
276 	}
277 }
main(int argc,char ** argv)278 int main(int argc, char **argv)
279 {
280 	char *output_file = NULL;
281 	char *entry_table_file = NULL;
282 	FILE *output = stdout;
283 	FILE *export_file;
284 	struct brw_program_instruction *entry, *entry1, *tmp_entry;
285 	int err, inst_offset;
286 	char o;
287 	void *mem_ctx;
288 
289 	while ((o = getopt_long(argc, argv, "e:l:o:g:abW", longopts, NULL)) != -1) {
290 		switch (o) {
291 		case 'o':
292 			if (strcmp(optarg, "-") != 0)
293 				output_file = optarg;
294 
295 			break;
296 
297 		case 'g': {
298 			char *dec_ptr, *end_ptr;
299 			unsigned long decimal;
300 
301 			gen_level = strtol(optarg, &dec_ptr, 10) * 10;
302 
303 			if (*dec_ptr == '.') {
304 				decimal = strtoul(++dec_ptr, &end_ptr, 10);
305 				if (end_ptr != dec_ptr && *end_ptr == '\0') {
306 					if (decimal > 10) {
307 						fprintf(stderr, "Invalid Gen X decimal version\n");
308 						exit(1);
309 					}
310 					gen_level += decimal;
311 				}
312 			}
313 
314 			if (gen_level < 40 || gen_level > 90) {
315 				usage();
316 				exit(1);
317 			}
318 
319 			break;
320 		}
321 
322 		case 'a':
323 			advanced_flag = 1;
324 			break;
325 		case 'b':
326 			binary_like_output = 1;
327 			break;
328 
329 		case 'e':
330 			need_export = 1;
331 			if (strcmp(optarg, "-") != 0)
332 				export_filename = optarg;
333 			break;
334 
335 		case 'l':
336 			if (strcmp(optarg, "-") != 0)
337 				entry_table_file = optarg;
338 			break;
339 
340 		case 'W':
341 			warning_flags |= WARN_ALL;
342 			break;
343 
344 		default:
345 			usage();
346 			exit(1);
347 		}
348 	}
349 	argc -= optind;
350 	argv += optind;
351 	if (argc != 1) {
352 		usage();
353 		exit(1);
354 	}
355 
356 	if (strcmp(argv[0], "-") != 0) {
357 		input_filename = argv[0];
358 		yyin = fopen(input_filename, "r");
359 		if (yyin == NULL) {
360 			perror("Couldn't open input file");
361 			exit(1);
362 		}
363 	}
364 
365 	brw_init_context(&genasm_brw_context, gen_level);
366 	mem_ctx = ralloc_context(NULL);
367 	brw_init_compile(&genasm_brw_context, &genasm_compile, mem_ctx);
368 
369 	err = yyparse();
370 
371 	if (strcmp(argv[0], "-"))
372 		fclose(yyin);
373 
374 	yylex_destroy();
375 
376 	if (err || errors)
377 		exit (1);
378 
379 	if (output_file) {
380 		output = fopen(output_file, "w");
381 		if (output == NULL) {
382 			perror("Couldn't open output file");
383 			exit(1);
384 		}
385 
386 	}
387 
388 	if (read_entry_file(entry_table_file)) {
389 		fprintf(stderr, "Read entry file error\n");
390 		exit(1);
391 	}
392 	inst_offset = 0 ;
393 	for (entry = compiled_program.first;
394 		entry != NULL; entry = entry->next) {
395 	    entry->inst_offset = inst_offset;
396 	    entry1 = entry->next;
397 	    if (entry1 && is_label(entry1) && is_entry_point(entry1)) {
398 		// insert NOP instructions until (inst_offset+1) % 4 == 0
399 		while (((inst_offset+1) % 4) != 0) {
400 		    tmp_entry = calloc(sizeof(*tmp_entry), 1);
401 		    tmp_entry->insn.gen.header.opcode = BRW_OPCODE_NOP;
402 		    entry->next = tmp_entry;
403 		    tmp_entry->next = entry1;
404 		    entry = tmp_entry;
405 		    tmp_entry->inst_offset = ++inst_offset;
406 		}
407 	    }
408 	    if (!is_label(entry))
409               inst_offset++;
410 	}
411 
412 	for (entry = compiled_program.first; entry; entry = entry->next)
413 	    if (is_label(entry))
414 		add_label(entry);
415 
416 	if (need_export) {
417 		if (export_filename) {
418 			export_file = fopen(export_filename, "w");
419 		} else {
420 			export_file = fopen("export.inc", "w");
421 		}
422 		for (entry = compiled_program.first;
423 			entry != NULL; entry = entry->next) {
424 		    if (is_label(entry))
425 			fprintf(export_file, "#define %s_IP %d\n",
426 				label_name(entry), (IS_GENx(5) ? 2 : 1)*(entry->inst_offset));
427 		}
428 		fclose(export_file);
429 	}
430 
431 	for (entry = compiled_program.first; entry; entry = entry->next) {
432 	    struct relocation *reloc = &entry->reloc;
433 
434 	    if (!is_relocatable(entry))
435 		continue;
436 
437 	    if (reloc->first_reloc_target)
438 		reloc->first_reloc_offset = label_to_addr(reloc->first_reloc_target, entry->inst_offset) - entry->inst_offset;
439 
440 	    if (reloc->second_reloc_target)
441 		reloc->second_reloc_offset = label_to_addr(reloc->second_reloc_target, entry->inst_offset) - entry->inst_offset;
442 
443 	    if (reloc->second_reloc_offset) { // this is a branch instruction with two offset arguments
444                 set_branch_two_offsets(entry, reloc->first_reloc_offset, reloc->second_reloc_offset);
445 	    } else if (reloc->first_reloc_offset) {
446                 set_branch_one_offset(entry, reloc->first_reloc_offset);
447 	    }
448 	}
449 
450 	if (binary_like_output)
451 		fprintf(output, "%s", binary_prepend);
452 
453 	for (entry = compiled_program.first;
454 		entry != NULL;
455 		entry = entry1) {
456 	    entry1 = entry->next;
457 	    if (!is_label(entry))
458 		print_instruction(output, &entry->insn.gen);
459 	    else
460 		free(entry->insn.label.name);
461 	    free(entry);
462 	}
463 	if (binary_like_output)
464 		fprintf(output, "};");
465 
466 	free_entry_point_table(entry_point_table);
467 	free_hash_table(declared_register_table);
468 	free_label_table(label_table);
469 
470 	fflush (output);
471 	if (ferror (output)) {
472 	    perror ("Could not flush output file");
473 	    if (output_file)
474 		unlink (output_file);
475 	    err = 1;
476 	}
477 	return err;
478 }
479