From b63782da16579f1343e97fbbff940ff084c7214e Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Fri, 23 Jun 2023 13:28:14 +0200 Subject: [PATCH] isaspec: Add "custom" field type Add support for a field which is decoded by a user callback. This will be used for decoding control registers in cread/cwrite by afuc. In order for this to interact well with the align feature, we need to pull print() out of the decode implementation so that the callback can call it and keep track of the line column. Part-of: --- src/compiler/isaspec/isa.py | 2 +- src/compiler/isaspec/isaspec.h | 16 ++++ src/compiler/isaspec/isaspec_decode_decl.h | 3 + src/compiler/isaspec/isaspec_decode_impl.c | 93 ++++++++++++---------- 4 files changed, 69 insertions(+), 45 deletions(-) diff --git a/src/compiler/isaspec/isa.py b/src/compiler/isaspec/isa.py index 501cb6d0be8..23e392bc619 100644 --- a/src/compiler/isaspec/isa.py +++ b/src/compiler/isaspec/isa.py @@ -494,7 +494,7 @@ class ISA(object): # Validate that all bitset fields have valid types, and in # the case of bitset type, the sizes match: - builtin_types = ['branch', 'absbranch', 'int', 'uint', 'hex', 'offset', 'uoffset', 'float', 'bool', 'enum'] + builtin_types = ['branch', 'absbranch', 'int', 'uint', 'hex', 'offset', 'uoffset', 'float', 'bool', 'enum', 'custom'] for bitset_name, bitset in self.bitsets.items(): if bitset.extends is not None: assert bitset.extends in self.bitsets, "{} extends invalid type: {}".format( diff --git a/src/compiler/isaspec/isaspec.h b/src/compiler/isaspec/isaspec.h index fdfc28117d3..da4ed3fb162 100644 --- a/src/compiler/isaspec/isaspec.h +++ b/src/compiler/isaspec/isaspec.h @@ -51,6 +51,17 @@ struct isa_entrypoint { uint32_t offset; }; +struct isa_print_state { + FILE *out; + + /** + * Column number of current line + */ + unsigned line_column; +}; + +void isa_print(struct isa_print_state *state, const char *fmt, ...) PRINTFLIKE(2, 3); + struct isa_decode_options { uint32_t gpu_id; @@ -83,6 +94,11 @@ struct isa_decode_options { */ void (*field_cb)(void *data, const char *field_name, struct isa_decode_value *val); + /** + * Callback for fields that need custom code to print their value. + */ + void (*field_print_cb)(struct isa_print_state *print, const char *field_name, uint64_t val); + /** * Callback prior to instruction decode */ diff --git a/src/compiler/isaspec/isaspec_decode_decl.h b/src/compiler/isaspec/isaspec_decode_decl.h index 93367f17edf..97f16fcd6ff 100644 --- a/src/compiler/isaspec/isaspec_decode_decl.h +++ b/src/compiler/isaspec/isaspec_decode_decl.h @@ -90,6 +90,9 @@ struct isa_field { TYPE_BOOL, TYPE_ENUM, + /* For fields that must be printed via a user-provided callback */ + TYPE_CUSTOM, + /* To assert a certain value in a given range of bits.. not * used for pattern matching, but allows an override to specify * that a certain bitpattern in some "unused" bits is expected diff --git a/src/compiler/isaspec/isaspec_decode_impl.c b/src/compiler/isaspec/isaspec_decode_impl.c index 3b2c59a4111..3b97931f77b 100644 --- a/src/compiler/isaspec/isaspec_decode_impl.c +++ b/src/compiler/isaspec/isaspec_decode_impl.c @@ -118,7 +118,8 @@ struct decode_scope { */ struct decode_state { const struct isa_decode_options *options; - FILE *out; + + struct isa_print_state print; /** * Current instruction being decoded: @@ -130,11 +131,6 @@ struct decode_state { */ unsigned num_instr; - /** - * Column number of current line - */ - unsigned line_column; - /** * Bitset of instructions that are branch targets (if options->branch_labels * is enabled) @@ -180,8 +176,8 @@ struct decode_state { char *errors[4]; }; -static void -print(struct decode_state *state, const char *fmt, ...) +void +isa_print(struct isa_print_state *state, const char *fmt, ...) { char *buffer; va_list args; @@ -203,7 +199,7 @@ print(struct decode_state *state, const char *fmt, ...) if (c == '\n') { state->line_column = 0; } - } + } free(buffer); @@ -237,9 +233,9 @@ flush_errors(struct decode_state *state) { unsigned num_errors = state->num_errors; if (num_errors > 0) - print(state, "\t; "); + isa_print(&state->print, "\t; "); for (unsigned i = 0; i < num_errors; i++) { - print(state, "%s%s", (i > 0) ? ", " : "", state->errors[i]); + isa_print(&state->print, "%s%s", (i > 0) ? ", " : "", state->errors[i]); free(state->errors[i]); } state->num_errors = 0; @@ -502,12 +498,12 @@ display_enum_field(struct decode_scope *scope, const struct isa_field *field, bi for (unsigned i = 0; i < e->num_values; i++) { if (e->values[i].val == ui) { - print(scope->state, "%s", e->values[i].display); + isa_print(&scope->state->print, "%s", e->values[i].display); return; } } - print(scope->state, "%u", (unsigned)ui); + isa_print(&scope->state->print, "%u", (unsigned)ui); } static const struct isa_field * @@ -566,6 +562,7 @@ display_field(struct decode_scope *scope, const char *field_name) { const struct isa_decode_options *options = scope->state->options; struct decode_state *state = scope->state; + struct isa_print_state *print = &state->print; size_t field_name_len = strlen(field_name); int num_align = 0; @@ -581,8 +578,8 @@ display_field(struct decode_scope *scope, const char *field_name) /* Special case ':algin=' should only do alignment */ if (field_name == align) { - while (scope->state->line_column < num_align) - print(state, " "); + while (scope->state->print.line_column < num_align) + isa_print(print, " "); return; } @@ -595,10 +592,10 @@ display_field(struct decode_scope *scope, const char *field_name) }); } - while (scope->state->line_column < num_align) - print(state, " "); + while (scope->state->print.line_column < num_align) + isa_print(print, " "); - print(scope->state, "%s", scope->bitset->name); + isa_print(print, "%s", scope->bitset->name); return; } @@ -620,8 +617,8 @@ display_field(struct decode_scope *scope, const char *field_name) unsigned width = 1 + field->high - field->low; - while (scope->state->line_column < num_align) - print(state, " "); + while (scope->state->print.line_column < num_align) + isa_print(print, " "); switch (field->type) { /* Basic types: */ @@ -636,10 +633,10 @@ display_field(struct decode_scope *scope, const char *field_name) } if (offset < scope->state->num_instr) { if (field->call) { - print(scope->state, "fxn%d", offset); + isa_print(print, "fxn%d", offset); BITSET_SET(scope->state->call_targets, offset); } else { - print(scope->state, "l%d", offset); + isa_print(print, "l%d", offset); BITSET_SET(scope->state->branch_targets, offset); } break; @@ -647,45 +644,53 @@ display_field(struct decode_scope *scope, const char *field_name) } FALLTHROUGH; case TYPE_INT: - print(scope->state, "%"PRId64, util_sign_extend(val, width)); + isa_print(print, "%"PRId64, util_sign_extend(val, width)); break; case TYPE_UINT: - print(scope->state, "%"PRIu64, val); + isa_print(print, "%"PRIu64, val); break; case TYPE_HEX: // TODO format # of digits based on field width? - print(scope->state, "%"PRIx64, val); + isa_print(print, "%"PRIx64, val); break; case TYPE_OFFSET: if (val != 0) { - print(scope->state, "%+"PRId64, util_sign_extend(val, width)); + isa_print(print, "%+"PRId64, util_sign_extend(val, width)); } break; case TYPE_UOFFSET: if (val != 0) { - print(scope->state, "+%"PRIu64, val); + isa_print(print, "+%"PRIu64, val); } break; case TYPE_FLOAT: if (width == 16) { - print(scope->state, "%f", _mesa_half_to_float(val)); + isa_print(print, "%f", _mesa_half_to_float(val)); } else { assert(width == 32); - print(scope->state, "%f", uif(val)); + isa_print(print, "%f", uif(val)); } break; case TYPE_BOOL: if (field->display) { if (val) { - print(scope->state, "%s", field->display); + isa_print(print, "%s", field->display); } } else { - print(scope->state, "%u", (unsigned)val); + isa_print(print, "%u", (unsigned)val); } break; case TYPE_ENUM: display_enum_field(scope, field, v); break; + case TYPE_CUSTOM: + /* The user has to provide a field_print_cb, but this can + * still be NULL during the branch offset pre-pass. + */ + if (state->options->field_print_cb) { + state->options->field_print_cb(print, field_name, val); + } + break; case TYPE_ASSERT: /* assert fields are not for display */ @@ -728,8 +733,8 @@ display(struct decode_scope *scope) p = e; } else { - fputc(*p, scope->state->out); - scope->state->line_column++; + fputc(*p, scope->state->print.out); + scope->state->print.line_column++; } p++; } @@ -747,7 +752,7 @@ decode(struct decode_state *state, void *bin, int sz) bitmask_t instr = { 0 }; next_instruction(&instr, &instrs[state->n * BITMASK_WORDS]); - state->line_column = 0; + state->print.line_column = 0; if (state->options->max_errors && (errors > state->options->max_errors)) { break; @@ -767,7 +772,7 @@ decode(struct decode_state *state, void *bin, int sz) state->options->instr_cb(state->options->cbdata, state->n, instr.bitset); } - print(state, "\n"); + isa_print(&state->print, "\n"); } while (state->next_entrypoint != state->end_entrypoint && @@ -776,7 +781,7 @@ decode(struct decode_state *state, void *bin, int sz) state->options->instr_cb(state->options->cbdata, state->n, instr.bitset); } - print(state, "%s:\n", state->next_entrypoint->name); + isa_print(&state->print, "%s:\n", state->next_entrypoint->name); state->next_entrypoint++; } @@ -785,7 +790,7 @@ decode(struct decode_state *state, void *bin, int sz) state->options->instr_cb(state->options->cbdata, state->n, instr.bitset); } - print(state, "fxn%d:\n", state->n); + isa_print(&state->print, "fxn%d:\n", state->n); } if (BITSET_TEST(state->branch_targets, state->n)) { @@ -793,7 +798,7 @@ decode(struct decode_state *state, void *bin, int sz) state->options->instr_cb(state->options->cbdata, state->n, instr.bitset); } - print(state, "l%d:\n", state->n); + isa_print(&state->print, "l%d:\n", state->n); } } @@ -804,9 +809,9 @@ decode(struct decode_state *state, void *bin, int sz) const struct isa_bitset *b = find_bitset(state, __instruction, instr); if (!b) { if (state->options->no_match_cb) { - state->options->no_match_cb(state->out, instr.bitset, BITMASK_WORDS); + state->options->no_match_cb(state->print.out, instr.bitset, BITMASK_WORDS); } else { - print(state, "no match: %"BITSET_FORMAT"\n", BITSET_VALUE(instr.bitset)); + isa_print(&state->print, "no match: %"BITSET_FORMAT"\n", BITSET_VALUE(instr.bitset)); } errors++; continue; @@ -820,7 +825,7 @@ decode(struct decode_state *state, void *bin, int sz) } else { errors = 0; } - print(state, "\n"); + isa_print(&state->print, "\n"); pop_scope(scope); @@ -860,10 +865,10 @@ isa_decode(void *bin, int sz, FILE *out, const struct isa_decode_options *option sizeof(BITSET_WORD) * BITSET_WORDS(state->num_instr)); /* Do a pre-pass to find all the branch targets: */ - state->out = fopen("/dev/null", "w"); + state->print.out = fopen("/dev/null", "w"); state->options = &default_options; /* skip hooks for prepass */ decode(state, bin, sz); - fclose(state->out); + fclose(state->print.out); if (options) { state->options = options; } @@ -884,7 +889,7 @@ isa_decode(void *bin, int sz, FILE *out, const struct isa_decode_options *option } } - state->out = out; + state->print.out = out; decode(state, bin, sz);