brw: Rework label tracking in assembler

For each label store its offset and two lists of uses (for JIP and UIP).
Because the parser itself already restricts what opcodes can use labels
(and which ones), don't re-validate them.

Reviewed-by: Sagar Ghuge <sagar.ghuge@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33522>
This commit is contained in:
Caio Oliveira 2025-02-12 15:04:29 -08:00
parent 7b45d31df0
commit ff59013571
3 changed files with 100 additions and 136 deletions

View file

@ -6,89 +6,100 @@
#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 list_head instr_labels;
struct list_head target_labels;
struct brw_codegen *p;
const char *input_filename;
int errors;
bool compaction_warning_given;
static bool
i965_postprocess_labels()
/*
* 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;
struct target_label *tlabel;
struct instr_label *ilabel, *s;
hash_table_foreach(brw_asm_labels, entry) {
brw_asm_label *label = entry->data;
const unsigned to_bytes_scale = brw_jump_scale(p->devinfo);
if (label->offset == -1) {
fprintf(stderr, "Unknown label '%s'\n", label->name);
unknown++;
continue;
}
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;
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);
}
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:
case BRW_OPCODE_GOTO:
case BRW_OPCODE_JOIN:
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:
case BRW_OPCODE_GOTO:
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);
}
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);
}
}
LIST_FOR_EACH_ENTRY(ilabel, &instr_labels, link) {
fprintf(stderr, "Unknown label '%s'\n", ilabel->name);
}
return list_is_empty(&instr_labels);
return unknown == 0;
}
/* TODO: Would be nice to make this operate on string instead on a FILE. */
@ -99,8 +110,8 @@ brw_assemble(void *mem_ctx, const struct intel_device_info *devinfo,
{
brw_assemble_result result = {0};
list_inithead(&instr_labels);
list_inithead(&target_labels);
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);
@ -116,7 +127,7 @@ brw_assemble(void *mem_ctx, const struct intel_device_info *devinfo,
if (err || errors)
goto end;
if (!i965_postprocess_labels())
if (!brw_postprocess_labels())
goto end;
struct disasm_info *disasm_info = disasm_initialize(p->isa, NULL);
@ -154,8 +165,9 @@ end:
yyin = NULL;
input_filename = NULL;
p = NULL;
list_inithead(&instr_labels);
list_inithead(&target_labels);
brw_asm_labels = NULL;
ralloc_free(tmp_ctx);
return result;
}

View file

@ -31,9 +31,6 @@ extern int errors;
extern bool compaction_warning_given;
extern const char *input_filename;
extern struct list_head instr_labels;
extern struct list_head target_labels;
struct condition {
unsigned cond_modifier:4;
unsigned flag_reg_nr:1;
@ -83,22 +80,6 @@ struct msgdesc {
unsigned src1_len:5;
};
enum instr_label_type {
INSTR_LABEL_JIP,
INSTR_LABEL_UIP,
};
struct instr_label {
struct list_head link;
char *name;
int offset;
enum instr_label_type type;
};
struct target_label {
struct list_head link;
char *name;
int offset;
};
void brw_asm_label_set(const char *name);
void brw_asm_label_use_jip(const char *name);
void brw_asm_label_use_uip(const char *name);

View file

@ -313,22 +313,6 @@ i965_asm_set_instruction_options(struct brw_codegen *p,
options.compaction);
}
static void
add_label(struct brw_codegen *p, const char* label_name, enum instr_label_type type)
{
if (!label_name) {
return;
}
struct instr_label *label = rzalloc(p->mem_ctx, struct instr_label);
label->name = ralloc_strdup(p->mem_ctx, label_name);
label->offset = p->next_insn_offset;
label->type = type;
list_addtail(&label->link, &instr_labels);
}
%}
%locations
@ -1101,9 +1085,8 @@ jumpinstruction:
branchinstruction:
predicate ENDIF execsize JIP JUMP_LABEL instoptions
{
add_label(p, $5, INSTR_LABEL_JIP);
brw_next_insn(p, $2);
brw_asm_label_use_jip($5);
i965_asm_set_instruction_options(p, $6);
brw_eu_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
@ -1113,10 +1096,9 @@ branchinstruction:
}
| ELSE execsize JIP JUMP_LABEL UIP JUMP_LABEL instoptions
{
add_label(p, $4, INSTR_LABEL_JIP);
add_label(p, $6, INSTR_LABEL_UIP);
brw_next_insn(p, $1);
brw_asm_label_use_jip($4);
brw_asm_label_use_uip($6);
i965_asm_set_instruction_options(p, $7);
brw_eu_inst_set_exec_size(p->devinfo, brw_last_inst, $2);
@ -1126,11 +1108,10 @@ branchinstruction:
}
| predicate IF execsize JIP JUMP_LABEL UIP JUMP_LABEL instoptions
{
add_label(p, $5, INSTR_LABEL_JIP);
add_label(p, $7, INSTR_LABEL_UIP);
brw_next_insn(p, $2);
i965_asm_set_instruction_options(p, $8);
brw_asm_label_use_jip($5);
brw_asm_label_use_uip($7);
brw_eu_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
brw_set_dest(p, brw_last_inst, vec1(retype(brw_null_reg(), BRW_TYPE_D)));
@ -1141,10 +1122,9 @@ branchinstruction:
}
| predicate GOTO execsize JIP JUMP_LABEL UIP JUMP_LABEL instoptions
{
add_label(p, $5, INSTR_LABEL_JIP);
add_label(p, $7, INSTR_LABEL_UIP);
brw_next_insn(p, $2);
brw_asm_label_use_jip($5);
brw_asm_label_use_uip($7);
i965_asm_set_instruction_options(p, $8);
brw_eu_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
@ -1155,9 +1135,8 @@ branchinstruction:
joininstruction:
predicate JOIN execsize JIP JUMP_LABEL instoptions
{
add_label(p, $5, INSTR_LABEL_JIP);
brw_next_insn(p, $2);
brw_asm_label_use_jip($5);
i965_asm_set_instruction_options(p, $6);
brw_eu_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
@ -1169,10 +1148,10 @@ joininstruction:
breakinstruction:
predicate BREAK execsize JIP JUMP_LABEL UIP JUMP_LABEL instoptions
{
add_label(p, $5, INSTR_LABEL_JIP);
add_label(p, $7, INSTR_LABEL_UIP);
brw_next_insn(p, $2);
brw_asm_label_use_jip($5);
brw_asm_label_use_uip($7);
i965_asm_set_instruction_options(p, $8);
brw_eu_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
@ -1183,10 +1162,9 @@ breakinstruction:
}
| predicate HALT execsize JIP JUMP_LABEL UIP JUMP_LABEL instoptions
{
add_label(p, $5, INSTR_LABEL_JIP);
add_label(p, $7, INSTR_LABEL_UIP);
brw_next_insn(p, $2);
brw_asm_label_use_jip($5);
brw_asm_label_use_uip($7);
i965_asm_set_instruction_options(p, $8);
brw_eu_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
@ -1200,10 +1178,9 @@ breakinstruction:
}
| predicate CONT execsize JIP JUMP_LABEL UIP JUMP_LABEL instoptions
{
add_label(p, $5, INSTR_LABEL_JIP);
add_label(p, $7, INSTR_LABEL_UIP);
brw_next_insn(p, $2);
brw_asm_label_use_jip($5);
brw_asm_label_use_uip($7);
i965_asm_set_instruction_options(p, $8);
brw_eu_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
brw_set_dest(p, brw_last_inst, brw_ip_reg());
@ -1218,9 +1195,8 @@ breakinstruction:
loopinstruction:
predicate WHILE execsize JIP JUMP_LABEL instoptions
{
add_label(p, $5, INSTR_LABEL_JIP);
brw_next_insn(p, $2);
brw_asm_label_use_jip($5);
i965_asm_set_instruction_options(p, $6);
brw_eu_inst_set_exec_size(p->devinfo, brw_last_inst, $3);
@ -1292,12 +1268,7 @@ relativelocation2:
jumplabeltarget:
JUMP_LABEL_TARGET
{
struct target_label *label = rzalloc(p->mem_ctx, struct target_label);
label->name = ralloc_strdup(p->mem_ctx, $1);
label->offset = p->next_insn_offset;
list_addtail(&label->link, &target_labels);
brw_asm_label_set($1);
}
;