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