1 /* -*- c-basic-offset: 8 -*- */
3 * Copyright © 2006 Intel Corporation
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:
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
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
25 * Eric Anholt <eric@anholt.net>
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);
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;
48 char *input_filename = "<stdin>";
51 struct brw_context genasm_brw_context;
52 struct brw_compile genasm_compile;
54 struct brw_program compiled_program;
55 struct program_defaults program_defaults = {.register_type = BRW_REGISTER_TYPE_F};
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";
67 struct hash_item *next;
70 typedef struct hash_item *hash_table[HASH_SIZE];
72 static hash_table declared_register_table;
77 struct label_item *next;
79 static struct label_item *label_table;
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'},
91 static void usage(void)
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> Specify GPU generation\n");
103 static int hash(char *key)
107 ret = (ret << 1) + (*key++);
108 return ret % HASH_SIZE;
111 static void *find_hash_item(hash_table t, char *key)
114 for(p = t[hash(key)]; p; p = p->next)
115 if(strcasecmp(p->key, key) == 0)
120 static void insert_hash_item(hash_table t, char *key, void *v)
122 int index = hash(key);
123 struct hash_item *p = malloc(sizeof(*p));
130 static void free_hash_table(hash_table t)
132 struct hash_item *p, *next;
134 for (i = 0; i < HASH_SIZE; i++) {
146 struct declared_register *find_register(char *name)
148 return find_hash_item(declared_register_table, name);
151 void insert_register(struct declared_register *reg)
153 insert_hash_item(declared_register_table, reg->name, reg);
156 static void add_label(struct brw_program_instruction *i)
158 struct label_item **p = &label_table;
164 *p = calloc(1, sizeof(**p));
165 (*p)->name = label_name(i);
166 (*p)->addr = i->inst_offset;
169 /* Some assembly code have duplicated labels.
170 Start from start_addr. Search as a loop. Return the first label found. */
171 static int label_to_addr(char *name, int start_addr)
173 /* return the first label just after start_addr, or the first label from the head */
174 struct label_item *p;
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
180 else if(r == -1) // the first label from the head
185 fprintf(stderr, "Can't find label %s\n", name);
191 static void free_label_table(struct label_item *p)
194 free_label_table(p->next);
199 struct entry_point_item {
201 struct entry_point_item *next;
202 } *entry_point_table;
204 static int read_entry_file(char *fn)
206 FILE *entry_table_file;
208 struct entry_point_item **p = &entry_point_table;
211 if ((entry_table_file = fopen(fn, "r")) == NULL)
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);
221 fclose(entry_table_file);
225 static int is_entry_point(struct brw_program_instruction *i)
227 struct entry_point_item *p;
229 assert(i->type == GEN4ASM_INSTRUCTION_LABEL);
231 for (p = entry_point_table; p; p = p->next) {
232 if (strcmp(p->str, i->insn.label.name) == 0)
238 static void free_entry_point_table(struct entry_point_item *p) {
240 free_entry_point_table(p->next);
247 print_instruction(FILE *output, struct brw_instruction *instruction)
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]);
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]);
278 int main(int argc, char **argv)
280 char *output_file = NULL;
281 char *entry_table_file = NULL;
282 FILE *output = stdout;
284 struct brw_program_instruction *entry, *entry1, *tmp_entry;
285 int err, inst_offset;
289 while ((o = getopt_long(argc, argv, "e:l:o:g:abW", longopts, NULL)) != -1) {
292 if (strcmp(optarg, "-") != 0)
293 output_file = optarg;
298 char *dec_ptr, *end_ptr;
299 unsigned long decimal;
301 gen_level = strtol(optarg, &dec_ptr, 10) * 10;
303 if (*dec_ptr == '.') {
304 decimal = strtoul(++dec_ptr, &end_ptr, 10);
305 if (end_ptr != dec_ptr && *end_ptr == '\0') {
307 fprintf(stderr, "Invalid Gen X decimal version\n");
310 gen_level += decimal;
314 if (gen_level < 40 || gen_level > 80) {
326 binary_like_output = 1;
331 if (strcmp(optarg, "-") != 0)
332 export_filename = optarg;
336 if (strcmp(optarg, "-") != 0)
337 entry_table_file = optarg;
341 warning_flags |= WARN_ALL;
356 if (strcmp(argv[0], "-") != 0) {
357 input_filename = argv[0];
358 yyin = fopen(input_filename, "r");
360 perror("Couldn't open input file");
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);
371 if (strcmp(argv[0], "-"))
380 output = fopen(output_file, "w");
381 if (output == NULL) {
382 perror("Couldn't open output file");
388 if (read_entry_file(entry_table_file)) {
389 fprintf(stderr, "Read entry file error\n");
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;
405 tmp_entry->inst_offset = ++inst_offset;
408 if (!is_label(entry))
412 for (entry = compiled_program.first; entry; entry = entry->next)
417 if (export_filename) {
418 export_file = fopen(export_filename, "w");
420 export_file = fopen("export.inc", "w");
422 for (entry = compiled_program.first;
423 entry != NULL; entry = entry->next) {
425 fprintf(export_file, "#define %s_IP %d\n",
426 label_name(entry), (IS_GENx(5) ? 2 : 1)*(entry->inst_offset));
431 for (entry = compiled_program.first; entry; entry = entry->next) {
432 struct relocation *reloc = &entry->reloc;
434 if (!is_relocatable(entry))
437 if (reloc->first_reloc_target)
438 reloc->first_reloc_offset = label_to_addr(reloc->first_reloc_target, entry->inst_offset) - entry->inst_offset;
440 if (reloc->second_reloc_target)
441 reloc->second_reloc_offset = label_to_addr(reloc->second_reloc_target, entry->inst_offset) - entry->inst_offset;
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);
450 if (binary_like_output)
451 fprintf(output, "%s", binary_prepend);
453 for (entry = compiled_program.first;
456 entry1 = entry->next;
457 if (!is_label(entry))
458 print_instruction(output, &entry->insn.gen);
460 free(entry->insn.label.name);
463 if (binary_like_output)
464 fprintf(output, "};");
466 free_entry_point_table(entry_point_table);
467 free_hash_table(declared_register_table);
468 free_label_table(label_table);
471 if (ferror (output)) {
472 perror ("Could not flush output file");
474 unlink (output_file);