blob: 239ff5fb2050139235bd0ac8d355facb280c591e [file] [log] [blame]
/*
* 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;
}