Path: blob/21.2-virgl/src/freedreno/rnn/rnndec.c
4565 views
/*1* Copyright (C) 2010-2011 Marcin KoĆcielnicki <[email protected]>2* Copyright (C) 2010 Francisco Jerez <[email protected]>3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the "Software"),7* to deal in the Software without restriction, including without limitation8* the rights to use, copy, modify, merge, publish, distribute, sublicense,9* and/or sell copies of the Software, and to permit persons to whom the10* Software is furnished to do so, subject to the following conditions:11*12* The above copyright notice and this permission notice (including the next13* paragraph) shall be included in all copies or substantial portions of the14* Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL19* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR20* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,21* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR22* OTHER DEALINGS IN THE SOFTWARE.23*/2425#include "rnndec.h"26#include <assert.h>27#include <stdio.h>28#include <string.h>29#include <stdlib.h>30#include <inttypes.h>31#include "util.h"32#include "util/compiler.h"3334struct rnndeccontext *rnndec_newcontext(struct rnndb *db) {35struct rnndeccontext *res = calloc (sizeof *res, 1);36res->db = db;37res->colors = &envy_null_colors;38return res;39}4041int rnndec_varadd(struct rnndeccontext *ctx, char *varset, const char *variant) {42struct rnnenum *en = rnn_findenum(ctx->db, varset);43if (!en) {44fprintf (stderr, "Enum %s doesn't exist in database!\n", varset);45return 0;46}47int i, j;48for (i = 0; i < en->valsnum; i++)49if (!strcasecmp(en->vals[i]->name, variant)) {50struct rnndecvariant *ci = calloc (sizeof *ci, 1);51ci->en = en;52ci->variant = i;53ADDARRAY(ctx->vars, ci);54return 1;55}5657if (i == en->valsnum) {58fprintf (stderr, "Variant %s doesn't exist in enum %s!\n", variant, varset);59return 0;60}6162for (j = 0; j < ctx->varsnum; j++) {63if (ctx->vars[j]->en == en) {64ctx->vars[j]->variant = i;65break;66}67}6869if (i == ctx->varsnum) {70struct rnndecvariant *ci = calloc (sizeof *ci, 1);71ci->en = en;72ci->variant = i;73ADDARRAY(ctx->vars, ci);74}7576return 1;77}7879int rnndec_varmatch(struct rnndeccontext *ctx, struct rnnvarinfo *vi) {80if (vi->dead)81return 0;82int i;83for (i = 0; i < vi->varsetsnum; i++) {84int j;85for (j = 0; j < ctx->varsnum; j++)86if (vi->varsets[i]->venum == ctx->vars[j]->en)87break;88if (j == ctx->varsnum) {89fprintf (stderr, "I don't know which %s variant to use!\n", vi->varsets[i]->venum->name);90} else {91if (!vi->varsets[i]->variants[ctx->vars[j]->variant])92return 0;93}94}95return 1;96}9798/* see https://en.wikipedia.org/wiki/Half-precision_floating-point_format */99static uint32_t float16i(uint16_t val)100{101uint32_t sign = ((uint32_t)(val & 0x8000)) << 16;102uint32_t frac = val & 0x3ff;103int32_t expn = (val >> 10) & 0x1f;104105if (expn == 0) {106if (frac) {107/* denormalized number: */108int shift = __builtin_clz(frac) - 21;109frac <<= shift;110expn = -shift;111} else {112/* +/- zero: */113return sign;114}115} else if (expn == 0x1f) {116/* Inf/NaN: */117return sign | 0x7f800000 | (frac << 13);118}119120return sign | ((expn + 127 - 15) << 23) | (frac << 13);121}122static float float16(uint16_t val)123{124union { uint32_t i; float f; } u;125u.i = float16i(val);126return u.f;127}128129static const char *rnndec_decode_enum_val(struct rnndeccontext *ctx,130struct rnnvalue **vals, int valsnum, uint64_t value)131{132int i;133for (i = 0; i < valsnum; i++)134if (rnndec_varmatch(ctx, &vals[i]->varinfo) &&135vals[i]->valvalid && vals[i]->value == value)136return vals[i]->name;137return NULL;138}139140const char *rnndec_decode_enum(struct rnndeccontext *ctx, const char *enumname, uint64_t enumval)141{142struct rnnenum *en = rnn_findenum (ctx->db, enumname);143if (en) {144return rnndec_decode_enum_val(ctx, en->vals, en->valsnum, enumval);145}146return NULL;147}148149/* The name UNK%u is used as a placeholder for bitfields that exist but150* have an unknown function.151*/152static int is_unknown(const char *name)153{154unsigned u;155return sscanf(name, "UNK%u", &u) == 1;156}157158char *rnndec_decodeval(struct rnndeccontext *ctx, struct rnntypeinfo *ti, uint64_t value) {159int width = ti->high - ti->low + 1;160char *res = 0;161int i;162struct rnnvalue **vals;163int valsnum;164struct rnnbitfield **bitfields;165int bitfieldsnum;166char *tmp;167const char *ctmp;168uint64_t mask, value_orig;169if (!ti)170goto failhex;171value_orig = value;172value = (value & typeinfo_mask(ti)) >> ti->low;173value <<= ti->shr;174175switch (ti->type) {176case RNN_TTYPE_ENUM:177vals = ti->eenum->vals;178valsnum = ti->eenum->valsnum;179goto doenum;180case RNN_TTYPE_INLINE_ENUM:181vals = ti->vals;182valsnum = ti->valsnum;183goto doenum;184doenum:185ctmp = rnndec_decode_enum_val(ctx, vals, valsnum, value);186if (ctmp) {187asprintf (&res, "%s%s%s", ctx->colors->eval, ctmp, ctx->colors->reset);188if (ti->addvariant) {189rnndec_varadd(ctx, ti->eenum->name, ctmp);190}191break;192}193goto failhex;194case RNN_TTYPE_BITSET:195bitfields = ti->ebitset->bitfields;196bitfieldsnum = ti->ebitset->bitfieldsnum;197goto dobitset;198case RNN_TTYPE_INLINE_BITSET:199bitfields = ti->bitfields;200bitfieldsnum = ti->bitfieldsnum;201goto dobitset;202dobitset:203mask = 0;204for (i = 0; i < bitfieldsnum; i++) {205if (!rnndec_varmatch(ctx, &bitfields[i]->varinfo))206continue;207uint64_t type_mask = typeinfo_mask(&bitfields[i]->typeinfo);208if (((value & type_mask) == 0) && is_unknown(bitfields[i]->name))209continue;210mask |= type_mask;211if (bitfields[i]->typeinfo.type == RNN_TTYPE_BOOLEAN) {212const char *color = is_unknown(bitfields[i]->name) ?213ctx->colors->err : ctx->colors->mod;214if (value & type_mask) {215if (!res)216asprintf (&res, "%s%s%s", color, bitfields[i]->name, ctx->colors->reset);217else {218asprintf (&tmp, "%s | %s%s%s", res, color, bitfields[i]->name, ctx->colors->reset);219free(res);220res = tmp;221}222}223continue;224}225char *subval;226if (is_unknown(bitfields[i]->name) && (bitfields[i]->typeinfo.type != RNN_TTYPE_A3XX_REGID)) {227uint64_t field_val = value & type_mask;228field_val = (field_val & typeinfo_mask(&bitfields[i]->typeinfo)) >> bitfields[i]->typeinfo.low;229field_val <<= bitfields[i]->typeinfo.shr;230asprintf (&subval, "%s%#"PRIx64"%s", ctx->colors->err, field_val, ctx->colors->reset);231} else {232subval = rnndec_decodeval(ctx, &bitfields[i]->typeinfo, value & type_mask);233}234if (!res)235asprintf (&res, "%s%s%s = %s", ctx->colors->rname, bitfields[i]->name, ctx->colors->reset, subval);236else {237asprintf (&tmp, "%s | %s%s%s = %s", res, ctx->colors->rname, bitfields[i]->name, ctx->colors->reset, subval);238free(res);239res = tmp;240}241free(subval);242}243if (value & ~mask) {244if (!res)245asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->err, value & ~mask, ctx->colors->reset);246else {247asprintf (&tmp, "%s | %s%#"PRIx64"%s", res, ctx->colors->err, value & ~mask, ctx->colors->reset);248free(res);249res = tmp;250}251}252if (!res)253asprintf (&res, "%s0%s", ctx->colors->num, ctx->colors->reset);254asprintf (&tmp, "{ %s }", res);255free(res);256return tmp;257case RNN_TTYPE_SPECTYPE:258return rnndec_decodeval(ctx, &ti->spectype->typeinfo, value);259case RNN_TTYPE_HEX:260asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->num, value, ctx->colors->reset);261break;262case RNN_TTYPE_FIXED:263if (value & UINT64_C(1) << (width-1)) {264asprintf (&res, "%s-%lf%s", ctx->colors->num,265((double)((UINT64_C(1) << width) - value)) / ((double)(1 << ti->radix)),266ctx->colors->reset);267break;268}269FALLTHROUGH;270case RNN_TTYPE_UFIXED:271asprintf (&res, "%s%lf%s", ctx->colors->num,272((double)value) / ((double)(1LL << ti->radix)),273ctx->colors->reset);274break;275case RNN_TTYPE_A3XX_REGID:276asprintf (&res, "%sr%"PRIu64".%c%s", ctx->colors->num, (value >> 2), "xyzw"[value & 0x3], ctx->colors->reset);277break;278case RNN_TTYPE_UINT:279asprintf (&res, "%s%"PRIu64"%s", ctx->colors->num, value, ctx->colors->reset);280break;281case RNN_TTYPE_INT:282if (value & UINT64_C(1) << (width-1))283asprintf (&res, "%s-%"PRIi64"%s", ctx->colors->num, (UINT64_C(1) << width) - value, ctx->colors->reset);284else285asprintf (&res, "%s%"PRIi64"%s", ctx->colors->num, value, ctx->colors->reset);286break;287case RNN_TTYPE_BOOLEAN:288if (value == 0) {289asprintf (&res, "%sFALSE%s", ctx->colors->eval, ctx->colors->reset);290} else if (value == 1) {291asprintf (&res, "%sTRUE%s", ctx->colors->eval, ctx->colors->reset);292}293break;294case RNN_TTYPE_FLOAT: {295union { uint64_t i; float f; double d; } val;296val.i = value;297if (width == 64)298asprintf(&res, "%s%f%s", ctx->colors->num,299val.d, ctx->colors->reset);300else if (width == 32)301asprintf(&res, "%s%f%s", ctx->colors->num,302val.f, ctx->colors->reset);303else if (width == 16)304asprintf(&res, "%s%f%s", ctx->colors->num,305float16(value), ctx->colors->reset);306else307goto failhex;308309break;310}311failhex:312default:313asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->num, value, ctx->colors->reset);314break;315}316if (value_orig & ~typeinfo_mask(ti)) {317asprintf (&tmp, "%s | %s%#"PRIx64"%s", res, ctx->colors->err, value_orig & ~typeinfo_mask(ti), ctx->colors->reset);318free(res);319res = tmp;320}321return res;322}323324static char *appendidx (struct rnndeccontext *ctx, char *name, uint64_t idx, struct rnnenum *index) {325char *res;326const char *index_name = NULL;327328if (index)329index_name = rnndec_decode_enum_val(ctx, index->vals, index->valsnum, idx);330331if (index_name)332asprintf (&res, "%s[%s%s%s]", name, ctx->colors->eval, index_name, ctx->colors->reset);333else334asprintf (&res, "%s[%s%#"PRIx64"%s]", name, ctx->colors->num, idx, ctx->colors->reset);335336free (name);337return res;338}339340/* This could probably be made to work for stripes too.. */341static int get_array_idx_offset(struct rnndelem *elem, uint64_t addr, uint64_t *idx, uint64_t *offset)342{343if (elem->offsets) {344int i;345for (i = 0; i < elem->offsetsnum; i++) {346uint64_t o = elem->offsets[i];347if ((o <= addr) && (addr < (o + elem->stride))) {348*idx = i;349*offset = addr - o;350return 0;351}352}353return -1;354} else {355if (addr < elem->offset)356return -1;357358*idx = (addr - elem->offset) / elem->stride;359*offset = (addr - elem->offset) % elem->stride;360361if (elem->length && (*idx >= elem->length))362return -1;363364return 0;365}366}367368static struct rnndecaddrinfo *trymatch (struct rnndeccontext *ctx, struct rnndelem **elems, int elemsnum, uint64_t addr, int write, int dwidth, uint64_t *indices, int indicesnum) {369struct rnndecaddrinfo *res;370int i, j;371for (i = 0; i < elemsnum; i++) {372if (!rnndec_varmatch(ctx, &elems[i]->varinfo))373continue;374uint64_t offset, idx;375char *tmp, *name;376switch (elems[i]->type) {377case RNN_ETYPE_REG:378if (addr < elems[i]->offset)379break;380if (elems[i]->stride) {381idx = (addr-elems[i]->offset)/elems[i]->stride;382offset = (addr-elems[i]->offset)%elems[i]->stride;383} else {384idx = 0;385offset = addr-elems[i]->offset;386}387if (offset >= elems[i]->width/dwidth)388break;389if (elems[i]->length && idx >= elems[i]->length)390break;391res = calloc (sizeof *res, 1);392res->typeinfo = &elems[i]->typeinfo;393res->width = elems[i]->width;394asprintf (&res->name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);395for (j = 0; j < indicesnum; j++)396res->name = appendidx(ctx, res->name, indices[j], NULL);397if (elems[i]->length != 1)398res->name = appendidx(ctx, res->name, idx, elems[i]->index);399if (offset) {400/* use _HI suffix for addresses */401if (offset == 1 &&402(!strcmp(res->typeinfo->name, "address") ||403!strcmp(res->typeinfo->name, "waddress"))) {404asprintf (&tmp, "%s_HI", res->name);405} else {406asprintf (&tmp, "%s+%s%#"PRIx64"%s", res->name, ctx->colors->err, offset, ctx->colors->reset);407}408free(res->name);409res->name = tmp;410}411return res;412case RNN_ETYPE_STRIPE:413for (idx = 0; idx < elems[i]->length || !elems[i]->length; idx++) {414if (addr < elems[i]->offset + elems[i]->stride * idx)415break;416offset = addr - (elems[i]->offset + elems[i]->stride * idx);417int extraidx = (elems[i]->length != 1);418int nindnum = (elems[i]->name ? 0 : indicesnum + extraidx);419uint64_t nind[nindnum];420if (!elems[i]->name) {421for (j = 0; j < indicesnum; j++)422nind[j] = indices[j];423if (extraidx)424nind[indicesnum] = idx;425}426res = trymatch (ctx, elems[i]->subelems, elems[i]->subelemsnum, offset, write, dwidth, nind, nindnum);427if (!res)428continue;429if (!elems[i]->name)430return res;431asprintf (&name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);432for (j = 0; j < indicesnum; j++)433name = appendidx(ctx, name, indices[j], NULL);434if (elems[i]->length != 1)435name = appendidx(ctx, name, idx, elems[i]->index);436asprintf (&tmp, "%s.%s", name, res->name);437free(name);438free(res->name);439res->name = tmp;440return res;441}442break;443case RNN_ETYPE_ARRAY:444if (get_array_idx_offset(elems[i], addr, &idx, &offset))445break;446asprintf (&name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);447for (j = 0; j < indicesnum; j++)448name = appendidx(ctx, name, indices[j], NULL);449if (elems[i]->length != 1)450name = appendidx(ctx, name, idx, elems[i]->index);451if ((res = trymatch (ctx, elems[i]->subelems, elems[i]->subelemsnum, offset, write, dwidth, 0, 0))) {452asprintf (&tmp, "%s.%s", name, res->name);453free(name);454free(res->name);455res->name = tmp;456return res;457}458res = calloc (sizeof *res, 1);459asprintf (&tmp, "%s+%s%#"PRIx64"%s", name, ctx->colors->err, offset, ctx->colors->reset);460free(name);461res->name = tmp;462return res;463default:464break;465}466}467return 0;468}469470int rnndec_checkaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write) {471struct rnndecaddrinfo *res = trymatch(ctx, domain->subelems, domain->subelemsnum, addr, write, domain->width, 0, 0);472if (res) {473free(res->name);474free(res);475}476return res != NULL;477}478479struct rnndecaddrinfo *rnndec_decodeaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write) {480struct rnndecaddrinfo *res = trymatch(ctx, domain->subelems, domain->subelemsnum, addr, write, domain->width, 0, 0);481if (res)482return res;483res = calloc (sizeof *res, 1);484asprintf (&res->name, "%s%#"PRIx64"%s", ctx->colors->err, addr, ctx->colors->reset);485return res;486}487488static unsigned tryreg(struct rnndeccontext *ctx, struct rnndelem **elems, int elemsnum,489int dwidth, const char *name, uint64_t *offset)490{491int i;492unsigned ret;493const char *suffix = strchr(name, '[');494unsigned n = suffix ? (suffix - name) : strlen(name);495const char *dotsuffix = strchr(name, '.');496unsigned dotn = dotsuffix ? (dotsuffix - name) : strlen(name);497498const char *child = NULL;499unsigned idx = 0;500501if (suffix) {502const char *tmp = strchr(suffix, ']');503idx = strtol(suffix+1, NULL, 0);504child = tmp+2;505}506507for (i = 0; i < elemsnum; i++) {508struct rnndelem *elem = elems[i];509if (!rnndec_varmatch(ctx, &elem->varinfo))510continue;511int match = elem->name && (strlen(elem->name) == n) && !strncmp(elem->name, name, n);512switch (elem->type) {513case RNN_ETYPE_REG:514if (match) {515assert(!suffix);516*offset = elem->offset;517return 1;518}519break;520case RNN_ETYPE_STRIPE:521if (elem->name) {522if (!dotsuffix)523break;524if (strlen(elem->name) != dotn || strncmp(elem->name, name, dotn))525break;526}527ret = tryreg(ctx, elem->subelems, elem->subelemsnum, dwidth,528elem->name ? dotsuffix : name, offset);529if (ret)530return 1;531break;532case RNN_ETYPE_ARRAY:533if (match) {534assert(suffix);535ret = tryreg(ctx, elem->subelems, elem->subelemsnum, dwidth, child, offset);536if (ret) {537*offset += elem->offset + (idx * elem->stride);538return 1;539}540}541break;542default:543break;544}545}546return 0;547}548549uint64_t rnndec_decodereg(struct rnndeccontext *ctx, struct rnndomain *domain, const char *name)550{551uint64_t offset;552if (tryreg(ctx, domain->subelems, domain->subelemsnum, domain->width, name, &offset)) {553return offset;554} else {555return 0;556}557}558559560