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