Path: blob/21.2-virgl/src/freedreno/isa/decode.c
4564 views
/*1* Copyright © 2020 Google, Inc.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*/2223#include <assert.h>24#include <inttypes.h>25#include <stdbool.h>26#include <stdint.h>27#include <stdio.h>28#include <stdlib.h>29#include <string.h>3031#include "util/bitset.h"32#include "util/compiler.h"33#include "util/half_float.h"34#include "util/hash_table.h"35#include "util/ralloc.h"36#include "util/u_debug.h"37#include "util/u_math.h"3839#include "decode.h"40#include "isa.h"4142/**43* The set of leaf node bitsets in the bitset hiearchy which defines all44* the possible instructions.45*46* TODO maybe we want to pass this in as parameter so this same decoder47* can work with multiple different instruction sets.48*/49extern const struct isa_bitset *__instruction[];5051struct decode_state;5253/**54* Decode scope. When parsing a field that is itself a bitset, we push a55* new scope to the stack. A nested bitset is allowed to resolve fields56* from an enclosing scope (needed, for example, to decode src register57* bitsets, where half/fullness is determined by fields outset if bitset58* in the instruction containing the bitset.59*60* But the field being resolved could be a derived field, or different61* depending on an override at a higher level of the stack, requiring62* expression evaluation which could in turn reference variables which63* triggers a recursive field lookup. But those lookups should not start64* from the top of the stack, but instead the current stack level. This65* prevents a field from accidentally resolving to different values66* depending on the starting point of the lookup. (Not only causing67* confusion, but this is behavior we don't want to depend on if we68* wanted to optimize things by caching field lookup results.)69*/70struct decode_scope {71/**72* Enclosing scope73*/74struct decode_scope *parent;7576/**77* Current bitset value being decoded78*/79uint64_t val;8081/**82* Current bitset.83*/84const struct isa_bitset *bitset;8586/**87* Field name remapping.88*/89const struct isa_field_params *params;9091/**92* Pointer back to decode state, for convenience.93*/94struct decode_state *state;9596/**97* Cache expression evaluation results. Expressions for overrides can98* be repeatedly evaluated for each field being resolved. And each99* field reference to a derived field (potentially from another expr)100* would require re-evaluation. But for a given scope, each evaluation101* of an expression gives the same result. So we can cache to speed102* things up.103*104* TODO we could maybe be clever and assign a unique idx to each expr105* and use a direct lookup table? Would be a bit more clever if it was106* smart enough to allow unrelated expressions that are never involved107* in a given scope to have overlapping cache lookup idx's.108*/109struct hash_table *cache;110};111112/**113* Current decode state114*/115struct decode_state {116const struct isa_decode_options *options;117FILE *out;118119/**120* Current instruction being decoded:121*/122unsigned n;123124/**125* Number of instructions being decoded126*/127unsigned num_instr;128129/**130* Bitset of instructions that are branch targets (if options->branch_labels131* is enabled)132*/133BITSET_WORD *branch_targets;134135/**136* We allow a limited amount of expression evaluation recursion, but137* not recursive evaluation of any given expression, to prevent infinite138* recursion.139*/140int expr_sp;141isa_expr_t expr_stack[8];142143/**144* Current topmost/innermost level of scope used for decoding fields,145* including derived fields which may in turn rely on decoding other146* fields, potentially from a lower/out level in the stack.147*/148struct decode_scope *scope;149150/**151* A small fixed upper limit on # of decode errors to capture per-152* instruction seems reasonable.153*/154unsigned num_errors;155char *errors[4];156};157158static void display(struct decode_scope *scope);159static void decode_error(struct decode_state *state, const char *fmt, ...) _util_printf_format(2,3);160161static void162decode_error(struct decode_state *state, const char *fmt, ...)163{164if (!state->options->show_errors) {165return;166}167168if (state->num_errors == ARRAY_SIZE(state->errors)) {169/* too many errors, bail */170return;171}172173va_list ap;174va_start(ap, fmt);175vasprintf(&state->errors[state->num_errors++], fmt, ap);176va_end(ap);177}178179static unsigned180flush_errors(struct decode_state *state)181{182unsigned num_errors = state->num_errors;183if (num_errors > 0)184fprintf(state->out, "\t; ");185for (unsigned i = 0; i < num_errors; i++) {186fprintf(state->out, "%s%s", (i > 0) ? ", " : "", state->errors[i]);187free(state->errors[i]);188}189state->num_errors = 0;190return num_errors;191}192193194static bool195push_expr(struct decode_state *state, isa_expr_t expr)196{197for (int i = state->expr_sp - 1; i > 0; i--) {198if (state->expr_stack[i] == expr) {199return false;200}201}202state->expr_stack[state->expr_sp++] = expr;203return true;204}205206static void207pop_expr(struct decode_state *state)208{209assert(state->expr_sp > 0);210state->expr_sp--;211}212213static struct decode_scope *214push_scope(struct decode_state *state, const struct isa_bitset *bitset, uint64_t val)215{216struct decode_scope *scope = rzalloc_size(state, sizeof(*scope));217218scope->val = val;219scope->bitset = bitset;220scope->parent = state->scope;221scope->state = state;222223state->scope = scope;224225return scope;226}227228static void229pop_scope(struct decode_scope *scope)230{231assert(scope->state->scope == scope); /* must be top of stack */232233scope->state->scope = scope->parent;234ralloc_free(scope);235}236237/**238* Evaluate an expression, returning it's resulting value239*/240static uint64_t241evaluate_expr(struct decode_scope *scope, isa_expr_t expr)242{243if (scope->cache) {244struct hash_entry *entry = _mesa_hash_table_search(scope->cache, expr);245if (entry) {246return *(uint64_t *)entry->data;247}248} else {249scope->cache = _mesa_pointer_hash_table_create(scope);250}251252if (!push_expr(scope->state, expr))253return 0;254255uint64_t ret = expr(scope);256257pop_expr(scope->state);258259uint64_t *retp = ralloc_size(scope->cache, sizeof(*retp));260*retp = ret;261_mesa_hash_table_insert(scope->cache, expr, retp);262263return ret;264}265266/**267* Find the bitset in NULL terminated bitset hiearchy root table which268* matches against 'val'269*/270static const struct isa_bitset *271find_bitset(struct decode_state *state, const struct isa_bitset **bitsets,272uint64_t val)273{274const struct isa_bitset *match = NULL;275for (int n = 0; bitsets[n]; n++) {276if (state->options->gpu_id > bitsets[n]->gen.max)277continue;278if (state->options->gpu_id < bitsets[n]->gen.min)279continue;280281uint64_t m = (val & bitsets[n]->mask) & ~bitsets[n]->dontcare;282283if (m != bitsets[n]->match) {284continue;285}286287/* We should only have exactly one match288*289* TODO more complete/formal way to validate that any given290* bit pattern will only have a single match?291*/292if (match) {293decode_error(state, "bitset conflict: %s vs %s", match->name,294bitsets[n]->name);295return NULL;296}297298match = bitsets[n];299}300301if (match && (match->dontcare & val)) {302decode_error(state, "dontcare bits in %s: %"PRIx64,303match->name, (match->dontcare & val));304}305306return match;307}308309static const struct isa_field *310find_field(struct decode_scope *scope, const struct isa_bitset *bitset,311const char *name)312{313for (unsigned i = 0; i < bitset->num_cases; i++) {314const struct isa_case *c = bitset->cases[i];315316if (c->expr) {317struct decode_state *state = scope->state;318319/* When resolving a field for evaluating an expression,320* temporarily assume the expression evaluates to true.321* This allows <override/>'s to speculatively refer to322* fields defined within the override:323*/324isa_expr_t cur_expr = NULL;325if (state->expr_sp > 0)326cur_expr = state->expr_stack[state->expr_sp - 1];327if ((cur_expr != c->expr) && !evaluate_expr(scope, c->expr))328continue;329}330331for (unsigned i = 0; i < c->num_fields; i++) {332if (!strcmp(name, c->fields[i].name)) {333return &c->fields[i];334}335}336}337338if (bitset->parent) {339const struct isa_field *f = find_field(scope, bitset->parent, name);340if (f) {341return f;342}343}344345return NULL;346}347348static uint64_t349extract_field(struct decode_scope *scope, const struct isa_field *field)350{351uint64_t val = scope->val;352val = (val >> field->low) & ((1ul << (1 + field->high - field->low)) - 1);353return val;354}355356/**357* Find the display template for a given bitset, recursively searching358* parents in the bitset hierarchy.359*/360static const char *361find_display(struct decode_scope *scope, const struct isa_bitset *bitset)362{363for (unsigned i = 0; i < bitset->num_cases; i++) {364const struct isa_case *c = bitset->cases[i];365if (c->expr && !evaluate_expr(scope, c->expr))366continue;367/* since this is the chosen case, it seems like a good place368* to check asserted bits:369*/370for (unsigned j = 0; j < c->num_fields; j++) {371if (c->fields[j].type == TYPE_ASSERT) {372const struct isa_field *f = &c->fields[j];373uint64_t val = extract_field(scope, f);374if (val != f->val) {375decode_error(scope->state, "WARNING: unexpected "376"bits[%u:%u] in %s: 0x%"PRIx64" vs 0x%"PRIx64,377f->low, f->high, bitset->name,378val, f->val);379}380}381}382if (!c->display)383continue;384return c->display;385}386387/**388* If we didn't find something check up the bitset hierarchy.389*/390if (bitset->parent) {391return find_display(scope, bitset->parent);392}393394return NULL;395}396397/**398* Decode a field that is itself another bitset type399*/400static void401display_bitset_field(struct decode_scope *scope, const struct isa_field *field, uint64_t val)402{403const struct isa_bitset *b = find_bitset(scope->state, field->bitsets, val);404if (!b) {405decode_error(scope->state, "no match: FIELD: '%s.%s': 0x%"PRIx64,406scope->bitset->name, field->name, val);407return;408}409410struct decode_scope *nested_scope =411push_scope(scope->state, b, val);412nested_scope->params = field->params;413display(nested_scope);414pop_scope(nested_scope);415}416417static void418display_enum_field(struct decode_scope *scope, const struct isa_field *field, uint64_t val)419{420FILE *out = scope->state->out;421422const struct isa_enum *e = field->enums;423for (unsigned i = 0; i < e->num_values; i++) {424if (e->values[i].val == val) {425fprintf(out, "%s", e->values[i].display);426return;427}428}429430fprintf(out, "%u", (unsigned)val);431}432433static const struct isa_field *434resolve_field(struct decode_scope *scope, const char *field_name, uint64_t *valp)435{436if (!scope) {437/* We've reached the bottom of the stack! */438return NULL;439}440441const struct isa_field *field =442find_field(scope, scope->bitset, field_name);443444if (!field && scope->params) {445for (unsigned i = 0; i < scope->params->num_params; i++) {446if (!strcmp(field_name, scope->params->params[i].as)) {447const char *param_name = scope->params->params[i].name;448return resolve_field(scope->parent, param_name, valp);449}450}451}452453if (!field) {454return NULL;455}456457/* extract out raw field value: */458if (field->expr) {459*valp = evaluate_expr(scope, field->expr);460} else {461*valp = extract_field(scope, field);462}463464return field;465}466467/* This is also used from generated expr functions */468uint64_t469isa_decode_field(struct decode_scope *scope, const char *field_name)470{471uint64_t val;472const struct isa_field *field = resolve_field(scope, field_name, &val);473if (!field) {474decode_error(scope->state, "no field '%s'", field_name);475return 0;476}477478return val;479}480481static void482display_field(struct decode_scope *scope, const char *field_name)483{484const struct isa_decode_options *options = scope->state->options;485486/* Special case 'NAME' maps to instruction/bitset name: */487if (!strcmp("NAME", field_name)) {488if (options->field_cb) {489options->field_cb(options->cbdata, field_name, &(struct isa_decode_value){490.str = scope->bitset->name,491});492}493494fprintf(scope->state->out, "%s", scope->bitset->name);495496return;497}498499uint64_t val;500const struct isa_field *field = resolve_field(scope, field_name, &val);501if (!field) {502decode_error(scope->state, "no field '%s'", field_name);503return;504}505506if (options->field_cb) {507options->field_cb(options->cbdata, field_name, &(struct isa_decode_value){508.num = val,509});510}511512unsigned width = 1 + field->high - field->low;513FILE *out = scope->state->out;514515switch (field->type) {516/* Basic types: */517case TYPE_BRANCH:518if (scope->state->options->branch_labels) {519int offset = util_sign_extend(val, width) + scope->state->n;520if (offset < scope->state->num_instr) {521fprintf(out, "l%d", offset);522BITSET_SET(scope->state->branch_targets, offset);523break;524}525}526FALLTHROUGH;527case TYPE_INT:528fprintf(out, "%"PRId64, util_sign_extend(val, width));529break;530case TYPE_UINT:531fprintf(out, "%"PRIu64, val);532break;533case TYPE_HEX:534// TODO format # of digits based on field width?535fprintf(out, "%"PRIx64, val);536break;537case TYPE_OFFSET:538if (val != 0) {539fprintf(out, "%+"PRId64, util_sign_extend(val, width));540}541break;542case TYPE_UOFFSET:543if (val != 0) {544fprintf(out, "+%"PRIu64, val);545}546break;547case TYPE_FLOAT:548if (width == 16) {549fprintf(out, "%f", _mesa_half_to_float(val));550} else {551assert(width == 32);552fprintf(out, "%f", uif(val));553}554break;555case TYPE_BOOL:556if (field->display) {557if (val) {558fprintf(out, "%s", field->display);559}560} else {561fprintf(out, "%u", (unsigned)val);562}563break;564case TYPE_ENUM:565display_enum_field(scope, field, val);566break;567568case TYPE_ASSERT:569/* assert fields are not for display */570assert(0);571break;572573/* For fields that are decoded with another bitset hierarchy: */574case TYPE_BITSET:575display_bitset_field(scope, field, val);576break;577default:578decode_error(scope->state, "Bad field type: %d (%s)",579field->type, field->name);580}581}582583static void584display(struct decode_scope *scope)585{586const struct isa_bitset *bitset = scope->bitset;587const char *display = find_display(scope, bitset);588589if (!display) {590decode_error(scope->state, "%s: no display template", bitset->name);591return;592}593594const char *p = display;595596while (*p != '\0') {597if (*p == '{') {598const char *e = ++p;599while (*e != '}') {600e++;601}602603char *field_name = strndup(p, e-p);604display_field(scope, field_name);605free(field_name);606607p = e;608} else {609fputc(*p, scope->state->out);610}611p++;612}613}614615static void616decode(struct decode_state *state, void *bin, int sz)617{618uint64_t *instrs = bin;619unsigned errors = 0; /* number of consecutive unmatched instructions */620621for (state->n = 0; state->n < state->num_instr; state->n++) {622uint64_t instr = instrs[state->n];623624if (state->options->max_errors && (errors > state->options->max_errors)) {625break;626}627628if (state->options->branch_labels &&629BITSET_TEST(state->branch_targets, state->n)) {630if (state->options->instr_cb) {631state->options->instr_cb(state->options->cbdata,632state->n, instr);633}634fprintf(state->out, "l%d:\n", state->n);635}636637if (state->options->instr_cb) {638state->options->instr_cb(state->options->cbdata, state->n, instr);639}640641const struct isa_bitset *b = find_bitset(state, __instruction, instr);642if (!b) {643fprintf(state->out, "no match: %016"PRIx64"\n", instr);644errors++;645continue;646}647648struct decode_scope *scope = push_scope(state, b, instr);649650display(scope);651if (flush_errors(state)) {652errors++;653} else {654errors = 0;655}656fprintf(state->out, "\n");657658pop_scope(scope);659660if (state->options->stop) {661break;662}663}664}665666void667isa_decode(void *bin, int sz, FILE *out, const struct isa_decode_options *options)668{669const struct isa_decode_options default_options = {670.branch_labels = options ? options->branch_labels : false671};672struct decode_state *state;673674if (!options)675options = &default_options;676677util_cpu_detect(); /* needed for _mesa_half_to_float() */678679state = rzalloc_size(NULL, sizeof(*state));680state->options = options;681state->num_instr = sz / 8;682683if (state->options->branch_labels) {684state->branch_targets = rzalloc_size(state,685sizeof(BITSET_WORD) * BITSET_WORDS(state->num_instr));686687/* Do a pre-pass to find all the branch targets: */688state->out = fopen("/dev/null", "w");689state->options = &default_options; /* skip hooks for prepass */690decode(state, bin, sz);691fclose(state->out);692if (options) {693state->options = options;694}695}696697state->out = out;698699decode(state, bin, sz);700701ralloc_free(state);702}703704705