intel/compiler: Get rid of the global compaction table pointers
[mesa.git] / src / intel / tools / i965_asm.c
index 1a53568abb5797957da4f69ba1bede89ddb7a553..7c42a6c8f1034c14add5a1f294050ceadeef1b2f 100644 (file)
 #include <getopt.h>
 #include "i965_asm.h"
 
+enum opt_output_type {
+   OPT_OUTPUT_HEX,
+   OPT_OUTPUT_C_LITERAL,
+   OPT_OUTPUT_BIN,
+};
+
 extern FILE *yyin;
 struct brw_codegen *p;
-static int c_literal_output = 0;
+static enum opt_output_type output_type = OPT_OUTPUT_BIN;
 char *input_filename = NULL;
 int errors;
 
+struct list_head instr_labels;
+struct list_head target_labels;
+
 static void
 print_help(const char *progname, FILE *file)
 {
@@ -39,16 +48,25 @@ print_help(const char *progname, FILE *file)
            "Usage: %s [OPTION] inputfile\n"
            "Assemble i965 instructions from input file.\n\n"
            "    -h, --help             display this help and exit\n"
-           "    -l, --c-literal        C literal\n"
+           "    -t, --type=OUTPUT_TYPE OUTPUT_TYPE can be 'bin' (default if omitted),\n"
+           "                           'c_literal', or 'hex'\n"
            "    -o, --output           specify output file\n"
            "        --compact          print compacted instructions\n"
            "    -g, --gen=platform     assemble instructions for given \n"
            "                           platform (3 letter platform name)\n"
            "Example:\n"
-           "    i965_asm -g kbl input.asm -o output\n",
+           "    i965_asm -g kbl input.asm -t hex -o output\n",
            progname);
 }
 
+static uint32_t
+get_dword(const brw_inst *inst, int idx)
+{
+   uint32_t dword;
+   memcpy(&dword, (char *)inst + 4 * idx, sizeof(dword));
+   return dword;
+}
+
 static void
 print_instruction(FILE *output, bool compact, const brw_inst *instruction)
 {
@@ -56,18 +74,31 @@ print_instruction(FILE *output, bool compact, const brw_inst *instruction)
 
    byte_limit = (compact == true) ? 8 : 16;
 
-   if (c_literal_output) {
-      fprintf(output, "\t0x%02x,", ((unsigned char *)instruction)[0]);
-
-      for (unsigned i = 1; i < byte_limit; i++)
-         fprintf(output, " 0x%02x,", ((unsigned char *)instruction)[i]);
-   } else {
+   switch (output_type) {
+   case OPT_OUTPUT_HEX: {
       fprintf(output, "%02x", ((unsigned char *)instruction)[0]);
 
-      for (unsigned i = 1; i < byte_limit; i++)
+      for (unsigned i = 1; i < byte_limit; i++) {
          fprintf(output, " %02x", ((unsigned char *)instruction)[i]);
+      }
+      break;
+   }
+   case OPT_OUTPUT_C_LITERAL: {
+      fprintf(output, "\t0x%08x,", get_dword(instruction, 0));
+
+      for (unsigned i = 1; i < byte_limit / 4; i++)
+         fprintf(output, " 0x%08x,", get_dword(instruction, i));
+
+      break;
+   }
+   case OPT_OUTPUT_BIN:
+      fwrite(instruction, 1, byte_limit, output);
+      break;
+   }
+
+   if (output_type != OPT_OUTPUT_BIN) {
+      fprintf(output, "\n");
    }
-   fprintf(output, "\n");
 }
 
 static struct gen_device_info *
@@ -79,17 +110,100 @@ i965_disasm_init(uint16_t pci_id)
    if (devinfo == NULL)
       return NULL;
 
-   if (!gen_get_device_info(pci_id, devinfo)) {
+   if (!gen_get_device_info_from_pci_id(pci_id, devinfo)) {
       fprintf(stderr, "can't find device information: pci_id=0x%x\n",
               pci_id);
+      free(devinfo);
       return NULL;
    }
 
-   brw_init_compaction_tables(devinfo);
-
    return devinfo;
 }
 
+static bool
+i965_postprocess_labels()
+{
+   if (p->devinfo->gen < 6) {
+      return true;
+   }
+
+   void *store = p->store;
+
+   struct target_label *tlabel;
+   struct instr_label *ilabel, *s;
+
+   const unsigned to_bytes_scale = brw_jump_scale(p->devinfo);
+
+   LIST_FOR_EACH_ENTRY(tlabel, &target_labels, link) {
+      LIST_FOR_EACH_ENTRY_SAFE(ilabel, s, &instr_labels, link) {
+         if (!strcmp(tlabel->name, ilabel->name)) {
+            brw_inst *inst = store + ilabel->offset;
+
+            int relative_offset = (tlabel->offset - ilabel->offset) / sizeof(brw_inst);
+            relative_offset *= to_bytes_scale;
+
+            unsigned opcode = brw_inst_opcode(p->devinfo, inst);
+
+            if (ilabel->type == INSTR_LABEL_JIP) {
+               switch (opcode) {
+               case BRW_OPCODE_IF:
+               case BRW_OPCODE_ELSE:
+               case BRW_OPCODE_ENDIF:
+               case BRW_OPCODE_WHILE:
+                  if (p->devinfo->gen >= 7) {
+                     brw_inst_set_jip(p->devinfo, inst, relative_offset);
+                  } else if (p->devinfo->gen == 6) {
+                     brw_inst_set_gen6_jump_count(p->devinfo, inst, relative_offset);
+                  }
+                  break;
+               case BRW_OPCODE_BREAK:
+               case BRW_OPCODE_HALT:
+               case BRW_OPCODE_CONTINUE:
+                  brw_inst_set_jip(p->devinfo, inst, relative_offset);
+                  break;
+               default:
+                  fprintf(stderr, "Unknown opcode %d with JIP label\n", opcode);
+                  return false;
+               }
+            } else {
+               switch (opcode) {
+               case BRW_OPCODE_IF:
+               case BRW_OPCODE_ELSE:
+                  if (p->devinfo->gen > 7) {
+                     brw_inst_set_uip(p->devinfo, inst, relative_offset);
+                  } else if (p->devinfo->gen == 7) {
+                     brw_inst_set_uip(p->devinfo, inst, relative_offset);
+                  } else if (p->devinfo->gen == 6) {
+                     // Nothing
+                  }
+                  break;
+               case BRW_OPCODE_WHILE:
+               case BRW_OPCODE_ENDIF:
+                  fprintf(stderr, "WHILE/ENDIF cannot have UIP offset\n");
+                  return false;
+               case BRW_OPCODE_BREAK:
+               case BRW_OPCODE_CONTINUE:
+               case BRW_OPCODE_HALT:
+                  brw_inst_set_uip(p->devinfo, inst, relative_offset);
+                  break;
+               default:
+                  fprintf(stderr, "Unknown opcode %d with UIP label\n", opcode);
+                  return false;
+               }
+            }
+
+            list_del(&ilabel->link);
+         }
+      }
+   }
+
+   LIST_FOR_EACH_ENTRY(ilabel, &instr_labels, link) {
+      fprintf(stderr, "Unknown label '%s'\n", ilabel->name);
+   }
+
+   return list_is_empty(&instr_labels);
+}
+
 int main(int argc, char **argv)
 {
    char *output_file = NULL;
@@ -101,19 +215,21 @@ int main(int argc, char **argv)
    int offset = 0, err;
    int start_offset = 0;
    struct disasm_info *disasm_info;
-   struct gen_device_info *devinfo;
+   struct gen_device_info *devinfo = NULL;
    int result = EXIT_FAILURE;
+   list_inithead(&instr_labels);
+   list_inithead(&target_labels);
 
    const struct option i965_asm_opts[] = {
       { "help",          no_argument,       (int *) &help,      true },
-      { "c-literal",     no_argument,       NULL,               'c' },
+      { "type",          required_argument, NULL,               't' },
       { "gen",           required_argument, NULL,               'g' },
       { "output",        required_argument, NULL,               'o' },
       { "compact",       no_argument,       (int *) &compact,   true },
       { NULL,            0,                 NULL,               0 }
    };
 
-   while ((c = getopt_long(argc, argv, ":g:o:lh", i965_asm_opts, NULL)) != -1) {
+   while ((c = getopt_long(argc, argv, ":t:g:o:h", i965_asm_opts, NULL)) != -1) {
       switch (c) {
       case 'g': {
          const int id = gen_device_name_to_pci_device_id(optarg);
@@ -130,9 +246,19 @@ int main(int argc, char **argv)
          help = true;
          print_help(argv[0], stderr);
          goto end;
-      case 'l':
-         c_literal_output = 1;
+      case 't': {
+         if (strcmp(optarg, "hex") == 0) {
+            output_type = OPT_OUTPUT_HEX;
+         } else if (strcmp(optarg, "c_literal") == 0) {
+            output_type = OPT_OUTPUT_C_LITERAL;
+         } else if (strcmp(optarg, "bin") == 0) {
+            output_type = OPT_OUTPUT_BIN;
+         } else {
+            fprintf(stderr, "invalid value for --type: %s\n", optarg);
+            goto end;
+         }
          break;
+      }
       case 'o':
          output_file = strdup(optarg);
          break;
@@ -191,6 +317,9 @@ int main(int argc, char **argv)
    if (err || errors)
       goto end;
 
+   if (!i965_postprocess_labels())
+      goto end;
+
    store = p->store;
 
    disasm_info = disasm_initialize(p->devinfo, NULL);
@@ -199,8 +328,8 @@ int main(int argc, char **argv)
       goto end;
    }
 
-   if (c_literal_output)
-      fprintf(output, "static const char gen_eu_bytes[] = {\n");
+   if (output_type == OPT_OUTPUT_C_LITERAL)
+      fprintf(output, "{\n");
 
    brw_validate_instructions(p->devinfo, p->store, 0,
                              p->next_insn_offset, disasm_info);
@@ -226,7 +355,7 @@ int main(int argc, char **argv)
 
    ralloc_free(disasm_info);
 
-   if (c_literal_output)
+   if (output_type == OPT_OUTPUT_C_LITERAL)
       fprintf(output, "}");
 
    result = EXIT_SUCCESS;