blob: f025f3e44adc2af8d254d3de166039d2b3a29317 [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"
/* TODO: Check if we can use bison/flex without globals. */
extern FILE *yyin;
struct list_head instr_labels;
struct list_head target_labels;
struct brw_codegen *p;
const char *input_filename;
int errors;
static bool
i965_postprocess_labels()
{
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_eu_inst *inst = store + ilabel->offset;
int relative_offset = (tlabel->offset - ilabel->offset) / sizeof(brw_eu_inst);
relative_offset *= to_bytes_scale;
unsigned opcode = brw_eu_inst_opcode(p->isa, 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:
brw_eu_inst_set_jip(p->devinfo, inst, relative_offset);
break;
case BRW_OPCODE_BREAK:
case BRW_OPCODE_HALT:
case BRW_OPCODE_CONTINUE:
brw_eu_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:
brw_eu_inst_set_uip(p->devinfo, inst, relative_offset);
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_eu_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);
}
/* 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};
list_inithead(&instr_labels);
list_inithead(&target_labels);
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;
int err = yyparse();
if (err || errors)
goto end;
if (!i965_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;
}
result.bin = p->store;
result.bin_size = p->next_insn_offset;
result.inst_count = p->next_insn_offset / 16;
if ((flags & BRW_ASSEMBLE_COMPACT) != 0) {
brw_compact_instructions(p, 0, disasm_info);
/* Adjust bin size to account for compacted instructions. */
int compacted = 0;
for (int i = 0; i < result.inst_count; i++) {
const brw_eu_inst *inst = result.bin + i;
if (brw_eu_inst_cmpt_control(devinfo, inst))
compacted++;
}
result.bin_size -= compacted * 8;
}
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;
list_inithead(&instr_labels);
list_inithead(&target_labels);
return result;
}