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