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