xref: /aosp_15_r20/external/mesa3d/src/intel/compiler/elk/elk_asm_tool.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2018 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 FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  *
23  */
24 
25 #include <stdio.h>
26 #include <getopt.h>
27 #include "elk_asm.h"
28 #include "elk_disasm_info.h"
29 
30 enum opt_output_type {
31    OPT_OUTPUT_HEX,
32    OPT_OUTPUT_C_LITERAL,
33    OPT_OUTPUT_BIN,
34 };
35 
36 extern FILE *yyin;
37 struct elk_codegen *p;
38 static enum opt_output_type output_type = OPT_OUTPUT_BIN;
39 char *input_filename = NULL;
40 int errors;
41 
42 struct list_head instr_labels;
43 struct list_head target_labels;
44 
45 static void
print_help(const char * progname,FILE * file)46 print_help(const char *progname, FILE *file)
47 {
48    fprintf(file,
49            "Usage: %s [OPTION] inputfile\n"
50            "Assemble i965 instructions from input file.\n\n"
51            "    -h, --help             display this help and exit\n"
52            "    -t, --type=OUTPUT_TYPE OUTPUT_TYPE can be 'bin' (default if omitted),\n"
53            "                           'c_literal', or 'hex'\n"
54            "    -o, --output           specify output file\n"
55            "        --compact          print compacted instructions\n"
56            "    -g, --gen=platform     assemble instructions for given \n"
57            "                           platform (3 letter platform name)\n"
58            "Example:\n"
59            "    i965_asm -g kbl input.asm -t hex -o output\n",
60            progname);
61 }
62 
63 static uint32_t
get_dword(const elk_inst * inst,int idx)64 get_dword(const elk_inst *inst, int idx)
65 {
66    uint32_t dword;
67    memcpy(&dword, (char *)inst + 4 * idx, sizeof(dword));
68    return dword;
69 }
70 
71 static void
print_instruction(FILE * output,bool compact,const elk_inst * instruction)72 print_instruction(FILE *output, bool compact, const elk_inst *instruction)
73 {
74    int byte_limit;
75 
76    byte_limit = (compact == true) ? 8 : 16;
77 
78    switch (output_type) {
79    case OPT_OUTPUT_HEX: {
80       fprintf(output, "%02x", ((unsigned char *)instruction)[0]);
81 
82       for (unsigned i = 1; i < byte_limit; i++) {
83          fprintf(output, " %02x", ((unsigned char *)instruction)[i]);
84       }
85       break;
86    }
87    case OPT_OUTPUT_C_LITERAL: {
88       fprintf(output, "\t0x%08x,", get_dword(instruction, 0));
89 
90       for (unsigned i = 1; i < byte_limit / 4; i++)
91          fprintf(output, " 0x%08x,", get_dword(instruction, i));
92 
93       break;
94    }
95    case OPT_OUTPUT_BIN:
96       fwrite(instruction, 1, byte_limit, output);
97       break;
98    }
99 
100    if (output_type != OPT_OUTPUT_BIN) {
101       fprintf(output, "\n");
102    }
103 }
104 
105 static struct intel_device_info *
i965_disasm_init(uint16_t pci_id)106 i965_disasm_init(uint16_t pci_id)
107 {
108    struct intel_device_info *devinfo;
109 
110    devinfo = malloc(sizeof *devinfo);
111    if (devinfo == NULL)
112       return NULL;
113 
114    if (!intel_get_device_info_from_pci_id(pci_id, devinfo)) {
115       fprintf(stderr, "can't find device information: pci_id=0x%x\n",
116               pci_id);
117       free(devinfo);
118       return NULL;
119    }
120 
121    return devinfo;
122 }
123 
124 static bool
i965_postprocess_labels()125 i965_postprocess_labels()
126 {
127    if (p->devinfo->ver < 6) {
128       return true;
129    }
130 
131    void *store = p->store;
132 
133    struct target_label *tlabel;
134    struct instr_label *ilabel, *s;
135 
136    const unsigned to_bytes_scale = elk_jump_scale(p->devinfo);
137 
138    LIST_FOR_EACH_ENTRY(tlabel, &target_labels, link) {
139       LIST_FOR_EACH_ENTRY_SAFE(ilabel, s, &instr_labels, link) {
140          if (!strcmp(tlabel->name, ilabel->name)) {
141             elk_inst *inst = store + ilabel->offset;
142 
143             int relative_offset = (tlabel->offset - ilabel->offset) / sizeof(elk_inst);
144             relative_offset *= to_bytes_scale;
145 
146             unsigned opcode = elk_inst_opcode(p->isa, inst);
147 
148             if (ilabel->type == INSTR_LABEL_JIP) {
149                switch (opcode) {
150                case ELK_OPCODE_IF:
151                case ELK_OPCODE_ELSE:
152                case ELK_OPCODE_ENDIF:
153                case ELK_OPCODE_WHILE:
154                   if (p->devinfo->ver >= 7) {
155                      elk_inst_set_jip(p->devinfo, inst, relative_offset);
156                   } else if (p->devinfo->ver == 6) {
157                      elk_inst_set_gfx6_jump_count(p->devinfo, inst, relative_offset);
158                   }
159                   break;
160                case ELK_OPCODE_BREAK:
161                case ELK_OPCODE_HALT:
162                case ELK_OPCODE_CONTINUE:
163                   elk_inst_set_jip(p->devinfo, inst, relative_offset);
164                   break;
165                default:
166                   fprintf(stderr, "Unknown opcode %d with JIP label\n", opcode);
167                   return false;
168                }
169             } else {
170                switch (opcode) {
171                case ELK_OPCODE_IF:
172                case ELK_OPCODE_ELSE:
173                   if (p->devinfo->ver > 7) {
174                      elk_inst_set_uip(p->devinfo, inst, relative_offset);
175                   } else if (p->devinfo->ver == 7) {
176                      elk_inst_set_uip(p->devinfo, inst, relative_offset);
177                   } else if (p->devinfo->ver == 6) {
178                      // Nothing
179                   }
180                   break;
181                case ELK_OPCODE_WHILE:
182                case ELK_OPCODE_ENDIF:
183                   fprintf(stderr, "WHILE/ENDIF cannot have UIP offset\n");
184                   return false;
185                case ELK_OPCODE_BREAK:
186                case ELK_OPCODE_CONTINUE:
187                case ELK_OPCODE_HALT:
188                   elk_inst_set_uip(p->devinfo, inst, relative_offset);
189                   break;
190                default:
191                   fprintf(stderr, "Unknown opcode %d with UIP label\n", opcode);
192                   return false;
193                }
194             }
195 
196             list_del(&ilabel->link);
197          }
198       }
199    }
200 
201    LIST_FOR_EACH_ENTRY(ilabel, &instr_labels, link) {
202       fprintf(stderr, "Unknown label '%s'\n", ilabel->name);
203    }
204 
205    return list_is_empty(&instr_labels);
206 }
207 
main(int argc,char ** argv)208 int main(int argc, char **argv)
209 {
210    char *output_file = NULL;
211    char c;
212    FILE *output = stdout;
213    bool help = false, compact = false;
214    void *store;
215    uint64_t pci_id = 0;
216    int offset = 0, err;
217    int start_offset = 0;
218    struct elk_disasm_info *elk_disasm_info;
219    struct intel_device_info *devinfo = NULL;
220    int result = EXIT_FAILURE;
221    list_inithead(&instr_labels);
222    list_inithead(&target_labels);
223 
224    const struct option i965_asm_opts[] = {
225       { "help",          no_argument,       (int *) &help,      true },
226       { "type",          required_argument, NULL,               't' },
227       { "gen",           required_argument, NULL,               'g' },
228       { "output",        required_argument, NULL,               'o' },
229       { "compact",       no_argument,       (int *) &compact,   true },
230       { NULL,            0,                 NULL,               0 }
231    };
232 
233    while ((c = getopt_long(argc, argv, ":t:g:o:h", i965_asm_opts, NULL)) != -1) {
234       switch (c) {
235       case 'g': {
236          const int id = intel_device_name_to_pci_device_id(optarg);
237          if (id < 0) {
238             fprintf(stderr, "can't parse gen: '%s', expected 3 letter "
239                             "platform name\n", optarg);
240             goto end;
241          } else {
242             pci_id = id;
243          }
244          break;
245       }
246       case 'h':
247          help = true;
248          print_help(argv[0], stderr);
249          goto end;
250       case 't': {
251          if (strcmp(optarg, "hex") == 0) {
252             output_type = OPT_OUTPUT_HEX;
253          } else if (strcmp(optarg, "c_literal") == 0) {
254             output_type = OPT_OUTPUT_C_LITERAL;
255          } else if (strcmp(optarg, "bin") == 0) {
256             output_type = OPT_OUTPUT_BIN;
257          } else {
258             fprintf(stderr, "invalid value for --type: %s\n", optarg);
259             goto end;
260          }
261          break;
262       }
263       case 'o':
264          output_file = strdup(optarg);
265          break;
266       case 0:
267          break;
268       case ':':
269          fprintf(stderr, "%s: option `-%c' requires an argument\n",
270                  argv[0], optopt);
271          goto end;
272       case '?':
273       default:
274          fprintf(stderr, "%s: option `-%c' is invalid: ignored\n",
275                  argv[0], optopt);
276          goto end;
277       }
278    }
279 
280    if (help || !pci_id) {
281       print_help(argv[0], stderr);
282       goto end;
283    }
284 
285    if (!argv[optind]) {
286       fprintf(stderr, "Please specify input file\n");
287       goto end;
288    }
289 
290    input_filename = strdup(argv[optind]);
291    yyin = fopen(input_filename, "r");
292    if (!yyin) {
293       fprintf(stderr, "Unable to read input file : %s\n",
294               input_filename);
295       goto end;
296    }
297 
298    if (output_file) {
299       output = fopen(output_file, "w");
300       if (!output) {
301          fprintf(stderr, "Couldn't open output file\n");
302          goto end;
303       }
304    }
305 
306    devinfo = i965_disasm_init(pci_id);
307    if (!devinfo) {
308       fprintf(stderr, "Unable to allocate memory for "
309                       "intel_device_info struct instance.\n");
310       goto end;
311    }
312 
313    struct elk_isa_info isa;
314    elk_init_isa_info(&isa, devinfo);
315 
316    p = rzalloc(NULL, struct elk_codegen);
317    elk_init_codegen(&isa, p, p);
318    p->automatic_exec_sizes = false;
319 
320    err = yyparse();
321    if (err || errors)
322       goto end;
323 
324    if (!i965_postprocess_labels())
325       goto end;
326 
327    store = p->store;
328 
329    elk_disasm_info = elk_disasm_initialize(p->isa, NULL);
330    if (!elk_disasm_info) {
331       fprintf(stderr, "Unable to initialize elk_disasm_info struct instance\n");
332       goto end;
333    }
334 
335    if (output_type == OPT_OUTPUT_C_LITERAL)
336       fprintf(output, "{\n");
337 
338    elk_validate_instructions(p->isa, p->store, 0,
339                              p->next_insn_offset, elk_disasm_info);
340 
341    const int nr_insn = (p->next_insn_offset - start_offset) / 16;
342 
343    if (compact)
344       elk_compact_instructions(p, start_offset, elk_disasm_info);
345 
346    for (int i = 0; i < nr_insn; i++) {
347       const elk_inst *insn = store + offset;
348       bool compacted = false;
349 
350       if (compact && elk_inst_cmpt_control(p->devinfo, insn)) {
351             offset += 8;
352             compacted = true;
353       } else {
354             offset += 16;
355       }
356 
357       print_instruction(output, compacted, insn);
358    }
359 
360    ralloc_free(elk_disasm_info);
361 
362    if (output_type == OPT_OUTPUT_C_LITERAL)
363       fprintf(output, "}");
364 
365    result = EXIT_SUCCESS;
366    goto end;
367 
368 end:
369    free(input_filename);
370    free(output_file);
371 
372    if (yyin)
373       fclose(yyin);
374 
375    if (output)
376       fclose(output);
377 
378    if (p)
379       ralloc_free(p);
380 
381    if (devinfo)
382       free(devinfo);
383 
384    exit(result);
385 }
386