/* * Copyright © 2018 Intel Corporation * SPDX-License-Identifier: MIT */ #include "brw_asm.h" #include "brw_asm_internal.h" #include "brw_disasm_info.h" #include "util/hash_table.h" #include "util/u_dynarray.h" /* TODO: Check if we can use bison/flex without globals. */ extern FILE *yyin; struct brw_codegen *p; const char *input_filename; int errors; bool compaction_warning_given; /* * Label tracking. */ static struct hash_table *brw_asm_labels; typedef struct { char *name; int offset; /* -1 for unset */ struct util_dynarray jip_uses; struct util_dynarray uip_uses; } brw_asm_label; static brw_asm_label * brw_asm_label_lookup(const char *name) { uint32_t h = _mesa_hash_string(name); struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(brw_asm_labels, h, name); if (!entry) { void *mem_ctx = brw_asm_labels; brw_asm_label *label = rzalloc(mem_ctx, brw_asm_label); label->name = ralloc_strdup(mem_ctx, name); label->offset = -1; util_dynarray_init(&label->jip_uses, mem_ctx); util_dynarray_init(&label->uip_uses, mem_ctx); entry = _mesa_hash_table_insert_pre_hashed(brw_asm_labels, h, name, label); } assert(entry); return entry->data; } void brw_asm_label_set(const char *name) { brw_asm_label *label = brw_asm_label_lookup(name); label->offset = p->next_insn_offset; } void brw_asm_label_use_jip(const char *name) { brw_asm_label *label = brw_asm_label_lookup(name); int offset = p->next_insn_offset - sizeof(brw_eu_inst); util_dynarray_append(&label->jip_uses, int, offset); } void brw_asm_label_use_uip(const char *name) { brw_asm_label *label = brw_asm_label_lookup(name); int offset = p->next_insn_offset - sizeof(brw_eu_inst); util_dynarray_append(&label->uip_uses, int, offset); } static bool brw_postprocess_labels() { unsigned unknown = 0; void *store = p->store; hash_table_foreach(brw_asm_labels, entry) { brw_asm_label *label = entry->data; if (label->offset == -1) { fprintf(stderr, "Unknown label '%s'\n", label->name); unknown++; continue; } util_dynarray_foreach(&label->jip_uses, int, use_offset) { brw_eu_inst *inst = store + *use_offset; brw_eu_inst_set_jip(p->devinfo, inst, label->offset - *use_offset); } util_dynarray_foreach(&label->uip_uses, int, use_offset) { brw_eu_inst *inst = store + *use_offset; brw_eu_inst_set_uip(p->devinfo, inst, label->offset - *use_offset); } } return unknown == 0; } /* TODO: Would be nice to make this operate on string instead on a FILE. */ brw_assemble_result brw_assemble(void *mem_ctx, const struct intel_device_info *devinfo, FILE *f, const char *filename, brw_assemble_flags flags) { brw_assemble_result result = {0}; void *tmp_ctx = ralloc_context(mem_ctx); brw_asm_labels = _mesa_string_hash_table_create(tmp_ctx); struct brw_isa_info isa; brw_init_isa_info(&isa, devinfo); p = rzalloc(mem_ctx, struct brw_codegen); brw_init_codegen(&isa, p, p); yyin = f; input_filename = filename; compaction_warning_given = false; int err = yyparse(); if (err || errors) goto end; if (!brw_postprocess_labels()) goto end; struct disasm_info *disasm_info = disasm_initialize(p->isa, NULL); if (!disasm_info) { ralloc_free(disasm_info); fprintf(stderr, "Unable to initialize disasm_info struct instance\n"); goto end; } /* Add "inst groups" so validation errors can be recorded. */ for (int i = 0; i <= p->next_insn_offset; i += 16) disasm_new_inst_group(disasm_info, i); if (!brw_validate_instructions(p->isa, p->store, 0, p->next_insn_offset, disasm_info)) { dump_assembly(p->store, 0, p->next_insn_offset, disasm_info, NULL); ralloc_free(disasm_info); fprintf(stderr, "Invalid instructions.\n"); goto end; } if ((flags & BRW_ASSEMBLE_COMPACT) != 0) brw_compact_instructions(p, 0, disasm_info); result.bin = p->store; result.bin_size = p->next_insn_offset; if ((flags & BRW_ASSEMBLE_DUMP) != 0) dump_assembly(p->store, 0, p->next_insn_offset, disasm_info, NULL); ralloc_free(disasm_info); end: /* Reset internal state. */ yyin = NULL; input_filename = NULL; p = NULL; brw_asm_labels = NULL; ralloc_free(tmp_ctx); return result; }