/* * 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_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->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_inst_set_jip(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: brw_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_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; } if (!brw_validate_instructions(p->isa, p->store, 0, p->next_insn_offset, disasm_info)) { 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_inst *inst = result.bin + i; if (brw_inst_cmpt_control(devinfo, inst)) compacted++; } result.bin_size -= compacted * 8; } 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; }