isaspec: Add "custom" field type
authorConnor Abbott <cwabbott0@gmail.com>
Fri, 23 Jun 2023 11:28:14 +0000 (13:28 +0200)
committerMarge Bot <emma+marge@anholt.net>
Fri, 28 Jul 2023 18:41:58 +0000 (18:41 +0000)
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: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23949>

src/compiler/isaspec/isa.py
src/compiler/isaspec/isaspec.h
src/compiler/isaspec/isaspec_decode_decl.h
src/compiler/isaspec/isaspec_decode_impl.c

index 501cb6d..23e392b 100644 (file)
@@ -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(
index fdfc281..da4ed3f 100644 (file)
@@ -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;
 
@@ -84,6 +95,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
         */
        void (*instr_cb)(void *data, unsigned n, void *instr);
index 93367f1..97f16fc 100644 (file)
@@ -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
index 3b2c59a..3b97931 100644 (file)
@@ -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:
@@ -131,11 +132,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);