Home | History | Annotate | Line # | Download | only in rnn
      1 /*
      2  * Copyright (C) 2010-2011 Marcin Kocielnicki <koriakin (at) 0x04.net>
      3  * Copyright (C) 2010 Francisco Jerez <currojerez (at) 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 
     35 struct 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 
     42 int 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 
     80 int 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 */
    100 static 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 }
    123 static 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 
    130 static 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 
    141 const 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  */
    153 static int is_unknown(const char *name)
    154 {
    155 	unsigned u;
    156 	return sscanf(name, "UNK%u", &u) == 1;
    157 }
    158 
    159 char *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 
    326 static 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.. */
    343 static 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 
    370 static 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 
    472 int 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 
    481 struct 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 
    490 static 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 
    551 uint64_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