xref: /third_party/mesa3d/src/freedreno/rnn/rnn.c (revision bf215546)
1/*
2 * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
3 * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.com>
4 * Copyright (C) 2010 Francisco Jerez <currojerez@riseup.net>
5 * Copyright (C) 2010 Martin Peres <martin.peres@ensi-bourges.fr>
6 * Copyright (C) 2010 Marcin Slusarz <marcin.slusarz@gmail.com>
7 * All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29/* workaround libxml2 silliness: */
30#pragma GCC diagnostic ignored "-Wpointer-sign"
31
32#include <libxml/xmlversion.h>
33#include <libxml/parser.h>
34#include <libxml/xpath.h>
35#include <libxml/xmlreader.h>
36#include <stdint.h>
37#include <string.h>
38#include <limits.h>
39#include <ctype.h>
40#include <stdio.h>
41#include "rnn.h"
42#include "util.h"
43
44#include "util/u_debug.h"
45
46static char *catstr (char *a, char *b) {
47	if (!a)
48		return b;
49	return aprintf("%s_%s", a, b);
50}
51
52static int strdiff (const char *a, const char *b) {
53	if (!a && !b)
54		return 0;
55	if (!a || !b)
56		return 1;
57	return strcmp (a, b);
58}
59
60static void rnn_err(struct rnndb *db, const char *format, ...) _util_printf_format(2, 3);
61
62static void rnn_err(struct rnndb *db, const char *format, ...)
63{
64	va_list ap;
65	va_start(ap, format);
66	vfprintf(stderr, format, ap);
67	va_end(ap);
68	db->estatus = 1;
69}
70
71void rnn_init(void) {
72	LIBXML_TEST_VERSION
73	xmlInitParser();
74}
75
76struct rnndb *rnn_newdb(void) {
77	struct rnndb *db = calloc(sizeof *db, 1);
78	return db;
79}
80
81static char *getcontent (xmlNode *attr) {
82	xmlNode *chain = attr->children;
83	size_t size = 0;
84	char *content, *p;
85	while (chain) {
86		if (chain->type == XML_TEXT_NODE)
87			size += strlen(chain->content);
88		chain = chain->next;
89	}
90	p = content = malloc(size + 1);
91	chain = attr->children;
92	while (chain) {
93		if (chain->type == XML_TEXT_NODE) {
94			char* sp = chain->content;
95			if(p == content) {
96				while(isspace(*sp))
97					++sp;
98			}
99			size_t len = strlen(sp);
100			memcpy(p, sp, len);
101			p += len;
102		}
103		chain = chain->next;
104	}
105	while(p != content && isspace(p[-1]))
106		--p;
107	*p = 0;
108	return content;
109}
110
111static char *getattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
112	xmlNode *chain = attr->children;
113	while (chain) {
114		if (chain->type != XML_TEXT_NODE) {
115			rnn_err(db, "%s:%d: unknown attribute child \"%s\" in attribute \"%s\"\n", file, line, chain->name, attr->name);
116		} else {
117			return chain->content;
118		}
119		chain = chain->next;
120	}
121	return "";
122}
123
124static int getboolattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
125	char *c = getattrib(db, file, line, attr);
126	if (!strcmp(c, "yes") || !strcmp(c, "1") || !strcmp(c, "true"))
127		return 1;
128	if (!strcmp(c, "no") || !strcmp(c, "0") || !strcmp(c, "false"))
129		return 0;
130	rnn_err(db, "%s:%d: invalid boolean value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
131	return 0;
132}
133
134static uint64_t getnum(struct rnndb *db, char *file, int line, xmlAttr *attr, char *c)
135{
136	char *cc;
137	uint64_t res;
138	if (strchr(c, 'x') || strchr(c, 'X'))
139		res = strtoull(c, &cc, 16);
140	else
141		res = strtoull(c, &cc, 10);
142	if (*cc)  {
143		rnn_err(db, "%s:%d: invalid numeric value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
144	}
145	return res;
146}
147
148static uint64_t getnumattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
149	char *c = getattrib(db, file, line, attr);
150	return getnum(db, file, line, attr, c);
151}
152
153static int trytop (struct rnndb *db, char *file, xmlNode *node);
154
155static int trydoc (struct rnndb *db, char *file, xmlNode *node) {
156	if (!strcmp(node->name, "brief")) {
157		return 1;
158	} else if (!strcmp(node->name, "doc")) {
159		return 1;
160	}
161	return 0;
162}
163
164static struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node);
165static struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *node);
166
167static int trytypetag (struct rnndb *db, char *file, xmlNode *node, struct rnntypeinfo *ti) {
168	if (!strcmp(node->name, "value")) {
169		struct rnnvalue *val = parsevalue(db, file, node);
170		if (val)
171			ADDARRAY(ti->vals, val);
172		return 1;
173	} else if (!strcmp(node->name, "bitfield")) {
174		struct rnnbitfield *bf = parsebitfield(db, file, node);
175		if (bf)
176			ADDARRAY(ti->bitfields, bf);
177		return 1;
178	}
179	return 0;
180}
181static int trytypeattr (struct rnndb *db, char *file, xmlNode *node, xmlAttr *attr, struct rnntypeinfo *ti) {
182	if (!strcmp(attr->name, "shr")) {
183		ti->shr = getnumattrib(db, file, node->line, attr);
184		return 1;
185	} else if (!strcmp(attr->name, "min")) {
186		ti->min = getnumattrib(db, file, node->line, attr);
187		ti->minvalid = 1;
188		return 1;
189	} else if (!strcmp(attr->name, "max")) {
190		ti->max = getnumattrib(db, file, node->line, attr);
191		ti->maxvalid = 1;
192		return 1;
193	} else if (!strcmp(attr->name, "align")) {
194		ti->align = getnumattrib(db, file, node->line, attr);
195		ti->alignvalid = 1;
196		return 1;
197	} else if (!strcmp(attr->name, "type")) {
198		ti->name = strdup(getattrib(db, file, node->line, attr));;
199		return 1;
200	} else if (!strcmp(attr->name, "radix")) {
201		ti->radix = getnumattrib(db, file, node->line, attr);
202		ti->radixvalid = 1;
203		return 1;
204	} else if (!strcmp(attr->name, "pos")) {
205		ti->high = ti->low = getnumattrib(db, file, node->line, attr);
206		return 1;
207	} else if (!strcmp(attr->name, "low")) {
208		ti->low = getnumattrib(db, file, node->line, attr);
209		return 1;
210	} else if (!strcmp(attr->name, "high")) {
211		ti->high = getnumattrib(db, file, node->line, attr);
212		return 1;
213	} else if (!strcmp(attr->name, "addvariant")) {
214		ti->addvariant = getboolattrib(db, file, node->line, attr);
215		return 1;
216	}
217	return 0;
218}
219
220static struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node) {
221	struct rnnvalue *val = calloc(sizeof *val, 1);
222	val->file = file;
223	xmlAttr *attr = node->properties;
224	while (attr) {
225		if (!strcmp(attr->name, "name")) {
226			val->name = strdup(getattrib(db, file, node->line, attr));
227		} else if (!strcmp(attr->name, "value")) {
228			val->value = getnumattrib(db, file, node->line, attr);
229			val->valvalid = 1;
230		} else if (!strcmp(attr->name, "varset")) {
231			val->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
232		} else if (!strcmp(attr->name, "variants")) {
233			val->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
234		} else {
235			rnn_err(db, "%s:%d: wrong attribute \"%s\" for value\n", file, node->line, attr->name);
236		}
237		attr = attr->next;
238	}
239	xmlNode *chain = node->children;
240	while (chain) {
241		if (chain->type != XML_ELEMENT_NODE) {
242		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
243			rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
244		}
245		chain = chain->next;
246	}
247	if (!val->name) {
248		rnn_err(db, "%s:%d: nameless value\n", file, node->line);
249		return 0;
250	} else {
251		return val;
252	}
253}
254
255static void parsespectype(struct rnndb *db, char *file, xmlNode *node) {
256	struct rnnspectype *res = calloc (sizeof *res, 1);
257	res->file = file;
258	xmlAttr *attr = node->properties;
259	int i;
260	while (attr) {
261		if (!strcmp(attr->name, "name")) {
262			res->name = strdup(getattrib(db, file, node->line, attr));
263		} else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
264			rnn_err(db, "%s:%d: wrong attribute \"%s\" for spectype\n", file, node->line, attr->name);
265		}
266		attr = attr->next;
267	}
268	if (!res->name) {
269		rnn_err(db, "%s:%d: nameless spectype\n", file, node->line);
270		return;
271	}
272	for (i = 0; i < db->spectypesnum; i++)
273		if (!strcmp(db->spectypes[i]->name, res->name)) {
274			rnn_err(db, "%s:%d: duplicated spectype name %s\n", file, node->line, res->name);
275			return;
276		}
277	ADDARRAY(db->spectypes, res);
278	xmlNode *chain = node->children;
279	while (chain) {
280		if (chain->type != XML_ELEMENT_NODE) {
281		} else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
282			rnn_err(db, "%s:%d: wrong tag in spectype: <%s>\n", file, chain->line, chain->name);
283		}
284		chain = chain->next;
285	}
286}
287
288static void parseenum(struct rnndb *db, char *file, xmlNode *node) {
289	xmlAttr *attr = node->properties;
290	char *name = 0;
291	int isinline = 0;
292	int bare = 0;
293	char *prefixstr = 0;
294	char *varsetstr = 0;
295	char *variantsstr = 0;
296	int i;
297	while (attr) {
298		if (!strcmp(attr->name, "name")) {
299			name = getattrib(db, file, node->line, attr);
300		} else if (!strcmp(attr->name, "bare")) {
301			bare = getboolattrib(db, file, node->line, attr);
302		} else if (!strcmp(attr->name, "inline")) {
303			isinline = getboolattrib(db, file, node->line, attr);
304		} else if (!strcmp(attr->name, "prefix")) {
305			prefixstr = strdup(getattrib(db, file, node->line, attr));
306		} else if (!strcmp(attr->name, "varset")) {
307			varsetstr = strdup(getattrib(db, file, node->line, attr));
308		} else if (!strcmp(attr->name, "variants")) {
309			variantsstr = strdup(getattrib(db, file, node->line, attr));
310		} else {
311			rnn_err(db, "%s:%d: wrong attribute \"%s\" for enum\n", file, node->line, attr->name);
312		}
313		attr = attr->next;
314	}
315	if (!name) {
316		rnn_err(db, "%s:%d: nameless enum\n", file, node->line);
317		return;
318	}
319	struct rnnenum *cur = 0;
320	for (i = 0; i < db->enumsnum; i++)
321		if (!strcmp(db->enums[i]->name, name)) {
322			cur = db->enums[i];
323			break;
324		}
325	if (cur) {
326		if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
327				strdiff(cur->varinfo.varsetstr, varsetstr) ||
328				strdiff(cur->varinfo.variantsstr, variantsstr) ||
329				cur->isinline != isinline || cur->bare != bare) {
330			rnn_err(db, "%s:%d: merge fail for enum %s\n", file, node->line, node->name);
331		}
332	} else {
333		cur = calloc(sizeof *cur, 1);
334		cur->name = strdup(name);
335		cur->isinline = isinline;
336		cur->bare = bare;
337		cur->varinfo.prefixstr = prefixstr;
338		cur->varinfo.varsetstr = varsetstr;
339		cur->varinfo.variantsstr = variantsstr;
340		cur->file = file;
341		ADDARRAY(db->enums, cur);
342	}
343	xmlNode *chain = node->children;
344	while (chain) {
345		if (chain->type != XML_ELEMENT_NODE) {
346		} else if (!strcmp(chain->name, "value")) {
347			struct rnnvalue *val = parsevalue(db, file, chain);
348			if (val)
349				ADDARRAY(cur->vals, val);
350		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
351			rnn_err(db, "%s:%d: wrong tag in enum: <%s>\n", file, chain->line, chain->name);
352		}
353		chain = chain->next;
354	}
355}
356
357static struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *node) {
358	struct rnnbitfield *bf = calloc(sizeof *bf, 1);
359	bf->file = file;
360	xmlAttr *attr = node->properties;
361	bf->typeinfo.low = bf->typeinfo.high = -1;
362	while (attr) {
363		if (!strcmp(attr->name, "name")) {
364			bf->name = strdup(getattrib(db, file, node->line, attr));
365		} else if (!strcmp(attr->name, "varset")) {
366			bf->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
367		} else if (!strcmp(attr->name, "variants")) {
368			bf->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
369		} else if (!trytypeattr(db, file, node, attr, &bf->typeinfo)) {
370			rnn_err(db, "%s:%d: wrong attribute \"%s\" for bitfield\n", file, node->line, attr->name);
371		}
372		attr = attr->next;
373	}
374	xmlNode *chain = node->children;
375	while (chain) {
376		if (chain->type != XML_ELEMENT_NODE) {
377		} else if (!trytypetag(db, file, chain, &bf->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
378			rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
379		}
380		chain = chain->next;
381	}
382	if (!bf->name) {
383		rnn_err(db, "%s:%d: nameless bitfield\n", file, node->line);
384		return 0;
385	} else if (bf->typeinfo.low < 0|| bf->typeinfo.high < 0 || bf->typeinfo.high < bf->typeinfo.low) {
386		rnn_err(db, "%s:%d: bitfield has wrong placement\n", file, node->line);
387		return 0;
388	} else {
389		return bf;
390	}
391}
392
393static void parsebitset(struct rnndb *db, char *file, xmlNode *node) {
394	xmlAttr *attr = node->properties;
395	char *name = 0;
396	int isinline = 0;
397	int bare = 0;
398	char *prefixstr = 0;
399	char *varsetstr = 0;
400	char *variantsstr = 0;
401	int i;
402	while (attr) {
403		if (!strcmp(attr->name, "name")) {
404			name = getattrib(db, file, node->line, attr);
405		} else if (!strcmp(attr->name, "bare")) {
406			bare = getboolattrib(db, file, node->line, attr);
407		} else if (!strcmp(attr->name, "inline")) {
408			isinline = getboolattrib(db, file, node->line, attr);
409		} else if (!strcmp(attr->name, "prefix")) {
410			prefixstr = strdup(getattrib(db, file, node->line, attr));
411		} else if (!strcmp(attr->name, "varset")) {
412			varsetstr = strdup(getattrib(db, file, node->line, attr));
413		} else if (!strcmp(attr->name, "variants")) {
414			variantsstr = strdup(getattrib(db, file, node->line, attr));
415		} else {
416			rnn_err(db, "%s:%d: wrong attribute \"%s\" for bitset\n", file, node->line, attr->name);
417		}
418		attr = attr->next;
419	}
420	if (!name) {
421		rnn_err(db, "%s:%d: nameless bitset\n", file, node->line);
422		return;
423	}
424	struct rnnbitset *cur = 0;
425	for (i = 0; i < db->bitsetsnum; i++)
426		if (!strcmp(db->bitsets[i]->name, name)) {
427			cur = db->bitsets[i];
428			break;
429		}
430	if (cur) {
431		if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
432				strdiff(cur->varinfo.varsetstr, varsetstr) ||
433				strdiff(cur->varinfo.variantsstr, variantsstr) ||
434				cur->isinline != isinline || cur->bare != bare) {
435			rnn_err(db, "%s:%d: merge fail for bitset %s\n", file, node->line, node->name);
436		}
437	} else {
438		cur = calloc(sizeof *cur, 1);
439		cur->name = strdup(name);
440		cur->isinline = isinline;
441		cur->bare = bare;
442		cur->varinfo.prefixstr = prefixstr;
443		cur->varinfo.varsetstr = varsetstr;
444		cur->varinfo.variantsstr = variantsstr;
445		cur->file = file;
446		ADDARRAY(db->bitsets, cur);
447	}
448	xmlNode *chain = node->children;
449	while (chain) {
450		if (chain->type != XML_ELEMENT_NODE) {
451		} else if (!strcmp(chain->name, "bitfield")) {
452			struct rnnbitfield *bf = parsebitfield(db, file, chain);
453			if (bf)
454				ADDARRAY(cur->bitfields, bf);
455		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
456			rnn_err(db, "%s:%d: wrong tag in bitset: <%s>\n", file, chain->line, chain->name);
457		}
458		chain = chain->next;
459	}
460}
461
462static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
463	if (!strcmp(node->name, "use-group")) {
464		struct rnndelem *res = calloc(sizeof *res, 1);
465		res->file = file;
466		res->type = RNN_ETYPE_USE_GROUP;
467		xmlAttr *attr = node->properties;
468		while (attr) {
469			if (!strcmp(attr->name, "ref")) {
470				res->name = strdup(getattrib(db, file, node->line, attr));
471			} else {
472				rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
473			}
474			attr = attr->next;
475		}
476		if (!res->name) {
477			rnn_err(db, "%s:%d: nameless use-group\n", file, node->line);
478			return 0;
479		}
480		return res;
481	} else if (!strcmp(node->name, "stripe") || !strcmp(node->name, "array")) {
482		struct rnndelem *res = calloc(sizeof *res, 1);
483		if (!strcmp(node->name, "array"))
484			res->name = "";
485		res->type = (strcmp(node->name, "stripe")?RNN_ETYPE_ARRAY:RNN_ETYPE_STRIPE);
486		res->length = 1;
487		res->file = file;
488		xmlAttr *attr = node->properties;
489		while (attr) {
490			if (!strcmp(attr->name, "name")) {
491				res->name = strdup(getattrib(db, file, node->line, attr));
492			} else if (!strcmp(attr->name, "offset")) {
493				res->offset = getnumattrib(db, file, node->line, attr);
494			} else if (!strcmp(attr->name, "offsets")) {
495				char *str = strdup(getattrib(db, file, node->line, attr));
496				char *tok, *save, *tmp = str;
497				while ((tok = strtok_r(str, ",", &save))) {
498					uint64_t offset = getnum(db, file, node->line, attr, tok);
499					ADDARRAY(res->offsets, offset);
500					str = NULL;
501				}
502				if (str)
503					fprintf(stderr, "%s:%d: invalid offsets: %s\n", file, node->line, str);
504				free(tmp);
505			} else if (!strcmp(attr->name, "doffset")) {
506				/* dynamic runtime determined offset: */
507				res->doffset = strdup(getattrib(db, file, node->line, attr));
508			} else if (!strcmp(attr->name, "doffsets")) {
509				/* dynamic runtime determined offsets: */
510				char *str = strdup(getattrib(db, file, node->line, attr));
511				char *tok, *save, *tmp = str;
512				while ((tok = strtok_r(str, ",", &save))) {
513					char *doffset = strdup(tok);
514					ADDARRAY(res->doffsets, doffset);
515					str = NULL;
516				}
517				if (str)
518					fprintf(stderr, "%s:%d: invalid offsets: %s\n", file, node->line, str);
519				free(tmp);
520			} else if (!strcmp(attr->name, "length")) {
521				res->length = getnumattrib(db, file, node->line, attr);
522			} else if (!strcmp(attr->name, "stride")) {
523				res->stride = getnumattrib(db, file, node->line, attr);
524			} else if (!strcmp(attr->name, "prefix")) {
525				res->varinfo.prefixstr = strdup(getattrib(db, file, node->line, attr));
526			} else if (!strcmp(attr->name, "varset")) {
527				res->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
528			} else if (!strcmp(attr->name, "variants")) {
529				res->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
530			} else if (!strcmp(attr->name, "index")) {
531				const char *enumname = getattrib(db, file, node->line, attr);
532				res->index = rnn_findenum(db, enumname);
533				if (!res->index) {
534					rnn_err(db, "%s:%d: invalid enum name \"%s\"\n", file, node->line, enumname);
535				}
536			} else {
537				rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
538			}
539			attr = attr->next;
540		}
541		xmlNode *chain = node->children;
542		while (chain) {
543			struct rnndelem *delem;
544			if (chain->type != XML_ELEMENT_NODE) {
545			} else if ((delem = trydelem(db, file, chain))) {
546				ADDARRAY(res->subelems, delem);
547			} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
548				rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
549			}
550			chain = chain->next;
551		}
552
553		/* Sanity checking */
554		if (res->type == RNN_ETYPE_ARRAY && res->stride == 0) {
555			fprintf(stderr, "%s: Array %s's stride is undefined. Aborting.\n", file, res->name);
556			exit(-1);
557		}
558		return res;
559
560	}
561	int width;
562	if (!strcmp(node->name, "reg8"))
563		width = 8;
564	else if (!strcmp(node->name, "reg16"))
565		width = 16;
566	else if (!strcmp(node->name, "reg32"))
567		width = 32;
568	else if (!strcmp(node->name, "reg64"))
569		width = 64;
570	else
571		return 0;
572	struct rnndelem *res = calloc(sizeof *res, 1);
573	res->file = file;
574	res->type = RNN_ETYPE_REG;
575	res->width = width;
576	res->length = 1;
577	res->access = RNN_ACCESS_RW;
578	xmlAttr *attr = node->properties;
579	res->typeinfo.low = 0;
580	res->typeinfo.high = width - 1;
581	while (attr) {
582		if (!strcmp(attr->name, "name")) {
583			res->name = strdup(getattrib(db, file, node->line, attr));
584		} else if (!strcmp(attr->name, "offset")) {
585			res->offset = getnumattrib(db, file, node->line, attr);
586		} else if (!strcmp(attr->name, "length")) {
587			res->length = getnumattrib(db, file, node->line, attr);
588		} else if (!strcmp(attr->name, "stride")) {
589			res->stride = getnumattrib(db, file, node->line, attr);
590		} else if (!strcmp(attr->name, "varset")) {
591			res->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
592		} else if (!strcmp(attr->name, "variants")) {
593			res->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
594		} else if (!strcmp(attr->name, "access")) {
595			char *str = getattrib(db, file, node->line, attr);
596			if (!strcmp(str, "r"))
597				res->access = RNN_ACCESS_R;
598			else if (!strcmp(str, "w"))
599				res->access = RNN_ACCESS_W;
600			else if (!strcmp(str, "rw"))
601				res->access = RNN_ACCESS_RW;
602			else
603				fprintf (stderr, "%s:%d: wrong access type \"%s\" for register\n", file, node->line, str);
604		} else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
605			rnn_err(db, "%s:%d: wrong attribute \"%s\" for register\n", file, node->line, attr->name);
606		}
607		attr = attr->next;
608	}
609	xmlNode *chain = node->children;
610	while (chain) {
611		if (chain->type != XML_ELEMENT_NODE) {
612		} else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
613			rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
614		}
615		chain = chain->next;
616	}
617	if (!res->name) {
618		rnn_err(db, "%s:%d: nameless register\n", file, node->line);
619		return 0;
620	} else {
621	}
622	return res;
623}
624
625static void parsegroup(struct rnndb *db, char *file, xmlNode *node) {
626	xmlAttr *attr = node->properties;
627	char *name = 0;
628	int i;
629	while (attr) {
630		if (!strcmp(attr->name, "name")) {
631			name = getattrib(db, file, node->line, attr);
632		} else {
633			rnn_err(db, "%s:%d: wrong attribute \"%s\" for group\n", file, node->line, attr->name);
634		}
635		attr = attr->next;
636	}
637	if (!name) {
638		rnn_err(db, "%s:%d: nameless group\n", file, node->line);
639		return;
640	}
641	struct rnngroup *cur = 0;
642	for (i = 0; i < db->groupsnum; i++)
643		if (!strcmp(db->groups[i]->name, name)) {
644			cur = db->groups[i];
645			break;
646		}
647	if (!cur) {
648		cur = calloc(sizeof *cur, 1);
649		cur->name = strdup(name);
650		ADDARRAY(db->groups, cur);
651	}
652	xmlNode *chain = node->children;
653	while (chain) {
654		struct rnndelem *delem;
655		if (chain->type != XML_ELEMENT_NODE) {
656		} else if ((delem = trydelem(db, file, chain))) {
657			ADDARRAY(cur->subelems, delem);
658		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
659			rnn_err(db, "%s:%d: wrong tag in group: <%s>\n", file, chain->line, chain->name);
660		}
661		chain = chain->next;
662	}
663}
664
665static void parsedomain(struct rnndb *db, char *file, xmlNode *node) {
666	xmlAttr *attr = node->properties;
667	char *name = 0;
668	uint64_t size = 0; int width = 8;
669	int bare = 0;
670	char *prefixstr = 0;
671	char *varsetstr = 0;
672	char *variantsstr = 0;
673	int i;
674	while (attr) {
675		if (!strcmp(attr->name, "name")) {
676			name = getattrib(db, file, node->line, attr);
677		} else if (!strcmp(attr->name, "bare")) {
678			bare = getboolattrib(db, file, node->line, attr);
679		} else if (!strcmp(attr->name, "size")) {
680			size = getnumattrib(db, file, node->line, attr);
681		} else if (!strcmp(attr->name, "width")) {
682			width = getnumattrib(db, file, node->line, attr);
683		} else if (!strcmp(attr->name, "prefix")) {
684			prefixstr = strdup(getattrib(db, file, node->line, attr));
685		} else if (!strcmp(attr->name, "varset")) {
686			varsetstr = strdup(getattrib(db, file, node->line, attr));
687		} else if (!strcmp(attr->name, "variants")) {
688			variantsstr = strdup(getattrib(db, file, node->line, attr));
689		} else {
690			rnn_err(db, "%s:%d: wrong attribute \"%s\" for domain\n", file, node->line, attr->name);
691		}
692		attr = attr->next;
693	}
694	if (!name) {
695		rnn_err(db, "%s:%d: nameless domain\n", file, node->line);
696		return;
697	}
698	struct rnndomain *cur = 0;
699	for (i = 0; i < db->domainsnum; i++)
700		if (!strcmp(db->domains[i]->name, name)) {
701			cur = db->domains[i];
702			break;
703		}
704	if (cur) {
705		if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
706				strdiff(cur->varinfo.varsetstr, varsetstr) ||
707				strdiff(cur->varinfo.variantsstr, variantsstr) ||
708				cur->width != width ||
709				cur->bare != bare ||
710				(size && cur->size && size != cur->size)) {
711			rnn_err(db, "%s:%d: merge fail for domain %s\n", file, node->line, node->name);
712		} else {
713			if (size)
714				cur->size = size;
715		}
716	} else {
717		cur = calloc(sizeof *cur, 1);
718		cur->name = strdup(name);
719		cur->bare = bare;
720		cur->width = width;
721		cur->size = size;
722		cur->varinfo.prefixstr = prefixstr;
723		cur->varinfo.varsetstr = varsetstr;
724		cur->varinfo.variantsstr = variantsstr;
725		cur->file = file;
726		ADDARRAY(db->domains, cur);
727	}
728	xmlNode *chain = node->children;
729	while (chain) {
730		struct rnndelem *delem;
731		if (chain->type != XML_ELEMENT_NODE) {
732		} else if ((delem = trydelem(db, file, chain))) {
733			ADDARRAY(cur->subelems, delem);
734		} else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
735			rnn_err(db, "%s:%d: wrong tag in domain: <%s>\n", file, chain->line, chain->name);
736		}
737		chain = chain->next;
738	}
739}
740
741static void parsecopyright(struct rnndb *db, char *file, xmlNode *node) {
742	struct rnncopyright* copyright = &db->copyright;
743	xmlAttr *attr = node->properties;
744	while (attr) {
745		if (!strcmp(attr->name, "year")) {
746			unsigned firstyear = getnumattrib(db, file, node->line, attr);
747			if(!copyright->firstyear || firstyear < copyright->firstyear)
748				copyright->firstyear = firstyear;
749		} else {
750			rnn_err(db, "%s:%d: wrong attribute \"%s\" for copyright\n", file, node->line, attr->name);
751		}
752		attr = attr->next;
753	}
754	xmlNode *chain = node->children;
755	while (chain) {
756		if (chain->type != XML_ELEMENT_NODE) {
757		} else if (!strcmp(chain->name, "license"))
758			if(copyright->license) {
759				if(strcmp(copyright->license, node->content)) {
760					fprintf(stderr, "fatal error: multiple different licenses specified!\n");
761					abort(); /* TODO: do something better here, but headergen, xml2html, etc. should not produce anything in this case */
762				}
763			} else
764				copyright->license = getcontent(chain);
765		else if (!strcmp(chain->name, "author")) {
766			struct rnnauthor* author = calloc(sizeof *author, 1);
767			xmlAttr* authorattr = chain->properties;
768			xmlNode *authorchild = chain->children;
769			author->contributions = getcontent(chain);
770			while (authorattr) {
771				if (!strcmp(authorattr->name, "name"))
772					author->name = strdup(getattrib(db, file, chain->line, authorattr));
773				else if (!strcmp(authorattr->name, "email"))
774					author->email = strdup(getattrib(db, file, chain->line, authorattr));
775				else {
776					rnn_err(db, "%s:%d: wrong attribute \"%s\" for author\n", file, chain->line, authorattr->name);
777				}
778				authorattr = authorattr->next;
779			}
780			while(authorchild)  {
781				if (authorchild->type != XML_ELEMENT_NODE) {
782				} else if (!strcmp(authorchild->name, "nick")) {
783					xmlAttr* nickattr = authorchild->properties;
784					char* nickname = 0;
785					while(nickattr) {
786						if (!strcmp(nickattr->name, "name"))
787							nickname = strdup(getattrib(db, file, authorchild->line, nickattr));
788						else {
789							rnn_err(db, "%s:%d: wrong attribute \"%s\" for nick\n", file, authorchild->line, nickattr->name);
790						}
791						nickattr = nickattr->next;
792					}
793					if(!nickname) {
794						rnn_err(db, "%s:%d: missing \"name\" attribute for nick\n", file, authorchild->line);
795					} else
796						ADDARRAY(author->nicknames, nickname);
797				} else {
798					rnn_err(db, "%s:%d: wrong tag in author: <%s>\n", file, authorchild->line, authorchild->name);
799				}
800				authorchild = authorchild->next;
801			}
802			ADDARRAY(copyright->authors, author);
803		} else {
804			rnn_err(db, "%s:%d: wrong tag in copyright: <%s>\n", file, chain->line, chain->name);
805		}
806		chain = chain->next;
807	}
808}
809
810static int trytop (struct rnndb *db, char *file, xmlNode *node) {
811	if (!strcmp(node->name, "enum")) {
812		parseenum(db, file, node);
813		return 1;
814	} else if (!strcmp(node->name, "bitset")) {
815		parsebitset(db, file, node);
816		return 1;
817	} else if (!strcmp(node->name, "group")) {
818		parsegroup(db, file, node);
819		return 1;
820	} else if (!strcmp(node->name, "domain")) {
821		parsedomain(db, file, node);
822		return 1;
823	} else if (!strcmp(node->name, "spectype")) {
824		parsespectype(db, file, node);
825		return 1;
826	} else if (!strcmp(node->name, "import")) {
827		xmlAttr *attr = node->properties;
828		char *subfile = 0;
829		while (attr) {
830			if (!strcmp(attr->name, "file")) {
831				subfile = getattrib(db, file, node->line, attr);
832			} else {
833				rnn_err(db, "%s:%d: wrong attribute \"%s\" for import\n", file, node->line, attr->name);
834			}
835			attr = attr->next;
836		}
837		if (!subfile) {
838			rnn_err(db, "%s:%d: missing \"file\" attribute for import\n", file, node->line);
839		} else {
840			rnn_parsefile(db, subfile);
841		}
842		return 1;
843	} else if (!strcmp(node->name, "copyright")) {
844		parsecopyright(db, file, node);
845		return 1;
846	}
847	return 0;
848}
849
850static char * find_file(const char *file_orig)
851{
852	const char *rnn_path = getenv("RNN_PATH");
853	char *fname;
854
855	if (!rnn_path)
856		rnn_path = RNN_DEF_PATH;
857
858	FILE *file = find_in_path(file_orig, rnn_path, &fname);
859	if (!file) {
860		fprintf (stderr, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", file_orig);
861		return NULL;
862	}
863	fclose(file);
864
865	return fname;
866}
867
868static int validate_doc(struct rnndb *db, xmlDocPtr doc, xmlNodePtr database)
869{
870	/* find the schemaLocation property: */
871	xmlAttrPtr attr = database->properties;
872	const char *schema_name = NULL;
873	char *schema_path;
874
875	while (attr) {
876		if (!strcmp(attr->name, "schemaLocation")) {
877			xmlNodePtr data = attr->children;
878			schema_name = data->content;
879			/* we expect this to look like <namespace url> schema.xsd.. I think
880			 * technically it is supposed to be just a URL, but that doesn't
881			 * quite match up to what we do.. Just skip over everything up to
882			 * and including the first whitespace character:
883			 */
884			while (schema_name && (schema_name[0] != ' '))
885				schema_name++;
886			schema_name++;
887			break;
888		}
889	}
890
891	if (!schema_name) {
892		rnn_err(db, "could not find schema.  Missing schemaLocation?");
893		return 0;
894	}
895
896	schema_path = find_file(schema_name);
897	if (!schema_path) {
898		rnn_err(db, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", schema_name);
899		return 0;
900	}
901
902	xmlSchemaParserCtxtPtr parser = xmlSchemaNewParserCtxt(schema_path);
903	xmlSchemaPtr schema = xmlSchemaParse(parser);
904	xmlSchemaValidCtxtPtr validCtxt = xmlSchemaNewValidCtxt(schema);
905	int ret = xmlSchemaValidateDoc(validCtxt, doc);
906
907	xmlSchemaFreeValidCtxt(validCtxt);
908	xmlSchemaFree(schema);
909	xmlSchemaFreeParserCtxt(parser);
910
911	free(schema_path);
912
913	return ret;
914}
915
916void rnn_parsefile (struct rnndb *db, char *file_orig) {
917	int i;
918	char *fname;
919
920	fname = find_file(file_orig);
921	if (!fname) {
922		db->estatus = 1;
923		return;
924	}
925
926	for (i = 0; i < db->filesnum; i++)
927		if (!strcmp(db->files[i], fname))
928			return;
929
930	ADDARRAY(db->files, fname);
931	xmlDocPtr doc = xmlParseFile(fname);
932	if (!doc) {
933		rnn_err(db, "%s: couldn't open database file. Please set the env var RNN_PATH.\n", fname);
934		return;
935	}
936	xmlNode *root = doc->children;
937	while (root) {
938		if (root->type != XML_ELEMENT_NODE) {
939		} else if (strcmp(root->name, "database")) {
940			rnn_err(db, "%s:%d: wrong top-level tag <%s>\n", fname, root->line, root->name);
941		} else {
942			xmlNode *chain = root->children;
943			if (validate_doc(db, doc, root)) {
944				rnn_err(db, "%s: database file has errors\n", fname);
945				return;
946			}
947			while (chain) {
948				if (chain->type != XML_ELEMENT_NODE) {
949				} else if (!trytop(db, fname, chain) && !trydoc(db, fname, chain)) {
950					rnn_err(db, "%s:%d: wrong tag in database: <%s>\n", fname, chain->line, chain->name);
951				}
952				chain = chain->next;
953			}
954		}
955		root = root->next;
956	}
957	xmlFreeDoc(doc);
958}
959
960static struct rnnvalue *copyvalue (struct rnnvalue *val, char *file) {
961	struct rnnvalue *res = calloc (sizeof *res, 1);
962	res->name = val->name;
963	res->valvalid = val->valvalid;
964	res->value = val->value;
965	res->varinfo = val->varinfo;
966	res->file = file;
967	return res;
968}
969
970static struct rnnbitfield *copybitfield (struct rnnbitfield *bf, char *file);
971
972
973static void copytypeinfo (struct rnntypeinfo *dst, struct rnntypeinfo *src, char *file) {
974	int i;
975	dst->name = src->name;
976	dst->shr = src->shr;
977	dst->low = src->low;
978	dst->high = src->high;
979	dst->min = src->min;
980	dst->max = src->max;
981	dst->align = src->align;
982	dst->addvariant = src->addvariant;
983	for (i = 0; i < src->valsnum; i++)
984		ADDARRAY(dst->vals, copyvalue(src->vals[i], file));
985	for (i = 0; i < src->bitfieldsnum; i++)
986		ADDARRAY(dst->bitfields, copybitfield(src->bitfields[i], file));
987}
988
989static struct rnnbitfield *copybitfield (struct rnnbitfield *bf, char *file) {
990	struct rnnbitfield *res = calloc (sizeof *res, 1);
991	res->name = bf->name;
992	res->varinfo = bf->varinfo;
993	res->file = file;
994	copytypeinfo(&res->typeinfo, &bf->typeinfo, file);
995	return res;
996}
997
998static struct rnndelem *copydelem (struct rnndelem *elem, char *file) {
999	struct rnndelem *res = calloc (sizeof *res, 1);
1000	res->type = elem->type;
1001	res->name = elem->name;
1002	res->width = elem->width;
1003	res->access = elem->access;
1004	res->offset = elem->offset;
1005	res->length = elem->length;
1006	res->stride = elem->stride;
1007	res->varinfo = elem->varinfo;
1008	res->file = file;
1009	copytypeinfo(&res->typeinfo, &elem->typeinfo, file);
1010	int i;
1011	for (i = 0; i < elem->subelemsnum; i++)
1012		ADDARRAY(res->subelems, copydelem(elem->subelems[i], file));
1013	for (i = 0; i < elem->offsetsnum; i++)
1014		ADDARRAY(res->offsets, elem->offsets[i]);
1015	return res;
1016}
1017
1018static struct rnnvarset *copyvarset (struct rnnvarset *varset) {
1019	struct rnnvarset *res = calloc(sizeof *res, 1);
1020	res->venum = varset->venum;
1021	res->variants = calloc(sizeof *res->variants, res->venum->valsnum);
1022	int i;
1023	for (i = 0; i < res->venum->valsnum; i++)
1024		res->variants[i] = varset->variants[i];
1025	return res;
1026}
1027
1028static void prepenum(struct rnndb *db, struct rnnenum *en);
1029
1030static int findvidx (struct rnndb *db, struct rnnenum *en, char *name) {
1031	int i;
1032	for (i = 0; i < en->valsnum; i++)
1033		if (!strcmp(en->vals[i]->name, name))
1034			return i;
1035	rnn_err(db, "Cannot find variant %s in enum %s!\n", name, en->name);
1036	return -1;
1037}
1038
1039static void prepvarinfo (struct rnndb *db, char *what, struct rnnvarinfo *vi, struct rnnvarinfo *parent) {
1040	if (parent)
1041		vi->prefenum = parent->prefenum;
1042	if (vi->prefixstr) {
1043		if (!strcmp(vi->prefixstr, "none"))
1044			vi->prefenum = 0;
1045		else
1046			vi->prefenum = rnn_findenum(db, vi->prefixstr); // XXX
1047	}
1048	int i;
1049	if (parent)
1050		for (i = 0; i < parent->varsetsnum; i++)
1051			ADDARRAY(vi->varsets, copyvarset(parent->varsets[i]));
1052	struct rnnenum *varset = vi->prefenum;
1053	if (!varset && !vi->varsetstr && parent)
1054		vi->varsetstr = parent->varsetstr;
1055	if (vi->varsetstr)
1056		varset = rnn_findenum(db, vi->varsetstr);
1057	if (vi->variantsstr) {
1058		char *vars = vi->variantsstr;
1059		if (!varset) {
1060			rnn_err(db, "%s: tried to use variants without active varset!\n", what);
1061			return;
1062		}
1063		struct rnnvarset *vs = 0;
1064		int nvars = varset->valsnum;
1065		for (i = 0; i < vi->varsetsnum; i++)
1066			if (vi->varsets[i]->venum == varset) {
1067				vs = vi->varsets[i];
1068				break;
1069			}
1070		if (!vs) {
1071			vs = calloc (sizeof *vs, 1);
1072			vs->venum = varset;
1073			vs->variants = calloc(sizeof *vs->variants, nvars);
1074			for (i = 0; i < nvars; i++)
1075				vs->variants[i] = 1;
1076			ADDARRAY(vi->varsets, vs);
1077		}
1078		while (1) {
1079			while (*vars == ' ') vars++;
1080			if (*vars == 0)
1081				break;
1082			char *split = vars;
1083			while (*split != ':' && *split != '-' && *split != ' '  && *split != 0)
1084				split++;
1085			char *first = 0;
1086			if (split != vars)
1087				first = strndup(vars, split-vars);
1088			if (*split == ' ' || *split == 0) {
1089				int idx = findvidx(db, varset, first);
1090				if (idx != -1)
1091					vs->variants[idx] |= 2;
1092				vars = split;
1093			} else {
1094				char *end = split+1;
1095				while (*end != ' '  && *end != 0)
1096					end++;
1097				char *second = 0;
1098				if (end != split+1)
1099					second = strndup(split+1, end-split-1);
1100				int idx1 = 0;
1101				if (first)
1102					idx1 = findvidx(db, varset, first);
1103				int idx2 = nvars;
1104				if (second) {
1105					idx2 = findvidx(db, varset, second);
1106					if (*split == '-')
1107						idx2++;
1108				}
1109				if (idx1 != -1 && idx2 != -1)
1110					for (i = idx1; i < idx2; i++)
1111						vs->variants[i] |= 2;
1112				vars = end;
1113				free(second);
1114			}
1115			free(first);
1116		}
1117		vi->dead = 1;
1118		for (i = 0; i < nvars; i++) {
1119			vs->variants[i] = (vs->variants[i] == 3);
1120			if (vs->variants[i])
1121				vi->dead = 0;
1122		}
1123	}
1124	if (vi->dead)
1125		return;
1126	if (vi->prefenum) {
1127		struct rnnvarset *vs = 0;
1128		for (i = 0; i < vi->varsetsnum; i++)
1129			if (vi->varsets[i]->venum == vi->prefenum) {
1130				vs = vi->varsets[i];
1131				break;
1132			}
1133		if (vs) {
1134			for (i = 0; i < vi->prefenum->valsnum; i++)
1135				if (vs->variants[i]) {
1136					vi->prefix = vi->prefenum->vals[i]->name;
1137					return;
1138				}
1139		} else {
1140			vi->prefix = vi->prefenum->vals[0]->name;
1141		}
1142	}
1143}
1144
1145static void prepvalue(struct rnndb *db, struct rnnvalue *val, char *prefix, struct rnnvarinfo *parvi) {
1146	val->fullname = catstr(prefix, val->name);
1147	prepvarinfo (db, val->fullname, &val->varinfo, parvi);
1148	if (val->varinfo.dead)
1149		return;
1150	if (val->varinfo.prefix)
1151		val->fullname = catstr(val->varinfo.prefix, val->fullname);
1152}
1153
1154static void prepbitfield(struct rnndb *db, struct rnnbitfield *bf, char *prefix, struct rnnvarinfo *parvi);
1155
1156static void preptypeinfo(struct rnndb *db, struct rnntypeinfo *ti, char *prefix, struct rnnvarinfo *vi, char *file) {
1157	int i;
1158	if (ti->name) {
1159		struct rnnenum *en = rnn_findenum (db, ti->name);
1160		struct rnnbitset *bs = rnn_findbitset (db, ti->name);
1161		struct rnnspectype *st = rnn_findspectype (db, ti->name);
1162		if (en) {
1163			if (en->isinline) {
1164				ti->type = RNN_TTYPE_INLINE_ENUM;
1165				int j;
1166				for (j = 0; j < en->valsnum; j++)
1167					ADDARRAY(ti->vals, copyvalue(en->vals[j], file));
1168			} else {
1169				ti->type = RNN_TTYPE_ENUM;
1170				ti->eenum = en;
1171			}
1172		} else if (bs) {
1173			if (bs->isinline) {
1174				ti->type = RNN_TTYPE_INLINE_BITSET;
1175				int j;
1176				for (j = 0; j < bs->bitfieldsnum; j++)
1177					ADDARRAY(ti->bitfields, copybitfield(bs->bitfields[j], file));
1178			} else {
1179				ti->type = RNN_TTYPE_BITSET;
1180				ti->ebitset = bs;
1181			}
1182		} else if (st) {
1183			ti->type = RNN_TTYPE_SPECTYPE;
1184			ti->spectype = st;
1185		} else if (!strcmp(ti->name, "hex")) {
1186			ti->type = RNN_TTYPE_HEX;
1187		} else if (!strcmp(ti->name, "float")) {
1188			ti->type = RNN_TTYPE_FLOAT;
1189		} else if (!strcmp(ti->name, "uint")) {
1190			ti->type = RNN_TTYPE_UINT;
1191		} else if (!strcmp(ti->name, "int")) {
1192			ti->type = RNN_TTYPE_INT;
1193		} else if (!strcmp(ti->name, "boolean")) {
1194			ti->type = RNN_TTYPE_BOOLEAN;
1195		} else if (!strcmp(ti->name, "bitfield")) {
1196			ti->type = RNN_TTYPE_INLINE_BITSET;
1197		} else if (!strcmp(ti->name, "enum")) {
1198			ti->type = RNN_TTYPE_INLINE_ENUM;
1199		} else if (!strcmp(ti->name, "fixed")) {
1200			ti->type = RNN_TTYPE_FIXED;
1201		} else if (!strcmp(ti->name, "ufixed")) {
1202			ti->type = RNN_TTYPE_UFIXED;
1203		} else if (!strcmp(ti->name, "a3xx_regid")) {
1204			ti->type = RNN_TTYPE_A3XX_REGID;
1205		} else if (!strcmp(ti->name, "waddress") || !strcmp(ti->name, "address")) {
1206			ti->type = RNN_TTYPE_HEX;
1207		} else {
1208			ti->type = RNN_TTYPE_HEX;
1209			rnn_err(db, "%s: unknown type %s\n", prefix, ti->name);
1210		}
1211	} else if (ti->bitfieldsnum) {
1212		ti->name = "bitfield";
1213		ti->type = RNN_TTYPE_INLINE_BITSET;
1214	} else if (ti->valsnum) {
1215		ti->name = "enum";
1216		ti->type = RNN_TTYPE_INLINE_ENUM;
1217	} else if (ti->low == 0 && ti->high == 0) {
1218		ti->name = "boolean";
1219		ti->type = RNN_TTYPE_BOOLEAN;
1220	} else {
1221		ti->name = "hex";
1222		ti->type = RNN_TTYPE_HEX;
1223	}
1224	if (ti->addvariant && ti->type != RNN_TTYPE_ENUM) {
1225		rnn_err(db, "%s: addvariant specified on non-enum type %s\n", prefix, ti->name);
1226	}
1227	for (i = 0; i < ti->bitfieldsnum; i++)
1228		prepbitfield(db,  ti->bitfields[i], prefix, vi);
1229	for (i = 0; i < ti->valsnum; i++)
1230		prepvalue(db, ti->vals[i], prefix, vi);
1231}
1232
1233static void prepbitfield(struct rnndb *db, struct rnnbitfield *bf, char *prefix, struct rnnvarinfo *parvi) {
1234	bf->fullname = catstr(prefix, bf->name);
1235	prepvarinfo (db, bf->fullname, &bf->varinfo, parvi);
1236	if (bf->varinfo.dead)
1237		return;
1238	preptypeinfo(db, &bf->typeinfo, bf->fullname, &bf->varinfo, bf->file);
1239	if (bf->varinfo.prefix)
1240		bf->fullname = catstr(bf->varinfo.prefix, bf->fullname);
1241}
1242
1243static void prepdelem(struct rnndb *db, struct rnndelem *elem, char *prefix, struct rnnvarinfo *parvi, int width) {
1244	if (elem->type == RNN_ETYPE_USE_GROUP) {
1245		int i;
1246		struct rnngroup *gr = 0;
1247		for (i = 0; i < db->groupsnum; i++)
1248			if (!strcmp(db->groups[i]->name, elem->name)) {
1249				gr = db->groups[i];
1250				break;
1251			}
1252		if (gr) {
1253			for (i = 0; i < gr->subelemsnum; i++)
1254				ADDARRAY(elem->subelems, copydelem(gr->subelems[i], elem->file));
1255		} else {
1256			rnn_err(db, "group %s not found!\n", elem->name);
1257		}
1258		elem->type = RNN_ETYPE_STRIPE;
1259		elem->length = 1;
1260		elem->name = 0;
1261	}
1262	if (elem->name)
1263		elem->fullname = catstr(prefix, elem->name);
1264	prepvarinfo (db, elem->fullname?elem->fullname:prefix, &elem->varinfo, parvi);
1265	if (elem->varinfo.dead)
1266		return;
1267	if (elem->length != 1 && !elem->stride) {
1268		if (elem->type != RNN_ETYPE_REG) {
1269			rnn_err(db, "%s has non-1 length, but no stride!\n", elem->fullname);
1270		} else {
1271			elem->stride = elem->width/width;
1272		}
1273	}
1274	preptypeinfo(db, &elem->typeinfo, elem->name?elem->fullname:prefix, &elem->varinfo, elem->file);
1275
1276	int i;
1277	for (i = 0; i < elem->subelemsnum; i++)
1278		prepdelem(db,  elem->subelems[i], elem->name?elem->fullname:prefix, &elem->varinfo, width);
1279	if (elem->varinfo.prefix && elem->name)
1280		elem->fullname = catstr(elem->varinfo.prefix, elem->fullname);
1281}
1282
1283static void prepdomain(struct rnndb *db, struct rnndomain *dom) {
1284	prepvarinfo (db, dom->name, &dom->varinfo, 0);
1285	int i;
1286	for (i = 0; i < dom->subelemsnum; i++)
1287		prepdelem(db, dom->subelems[i], dom->bare?0:dom->name, &dom->varinfo, dom->width);
1288	dom->fullname = catstr(dom->varinfo.prefix, dom->name);
1289}
1290
1291static void prepenum(struct rnndb *db, struct rnnenum *en) {
1292	if (en->prepared)
1293		return;
1294	prepvarinfo (db, en->name, &en->varinfo, 0);
1295	int i;
1296	if (en->isinline)
1297		return;
1298	for (i = 0; i < en->valsnum; i++)
1299		prepvalue(db, en->vals[i], en->bare?0:en->name, &en->varinfo);
1300	en->fullname = catstr(en->varinfo.prefix, en->name);
1301	en->prepared = 1;
1302}
1303
1304static void prepbitset(struct rnndb *db, struct rnnbitset *bs) {
1305	prepvarinfo (db, bs->name, &bs->varinfo, 0);
1306	int i;
1307	if (bs->isinline)
1308		return;
1309	for (i = 0; i < bs->bitfieldsnum; i++)
1310		prepbitfield(db, bs->bitfields[i], bs->bare?0:bs->name, &bs->varinfo);
1311	bs->fullname = catstr(bs->varinfo.prefix, bs->name);
1312}
1313
1314static void prepspectype(struct rnndb *db, struct rnnspectype *st) {
1315	preptypeinfo(db, &st->typeinfo, st->name, 0, st->file); // XXX doesn't exactly make sense...
1316}
1317
1318void rnn_prepdb (struct rnndb *db) {
1319	int i;
1320	for (i = 0; i < db->enumsnum; i++)
1321		prepenum(db, db->enums[i]);
1322	for (i = 0; i < db->bitsetsnum; i++)
1323		prepbitset(db, db->bitsets[i]);
1324	for (i = 0; i < db->domainsnum; i++)
1325		prepdomain(db, db->domains[i]);
1326	for (i = 0; i < db->spectypesnum; i++)
1327		prepspectype(db, db->spectypes[i]);
1328}
1329
1330struct rnnenum *rnn_findenum (struct rnndb *db, const char *name) {
1331	int i;
1332	for (i = 0; i < db->enumsnum; i++)
1333		if (!strcmp(db->enums[i]->name, name))
1334			return db->enums[i];
1335	return 0;
1336}
1337
1338struct rnnbitset *rnn_findbitset (struct rnndb *db, const char *name) {
1339	int i;
1340	for (i = 0; i < db->bitsetsnum; i++)
1341		if (!strcmp(db->bitsets[i]->name, name))
1342			return db->bitsets[i];
1343	return 0;
1344}
1345
1346struct rnndomain *rnn_finddomain (struct rnndb *db, const char *name) {
1347	int i;
1348	for (i = 0; i < db->domainsnum; i++)
1349		if (!strcmp(db->domains[i]->name, name))
1350			return db->domains[i];
1351	return 0;
1352}
1353
1354struct rnnspectype *rnn_findspectype (struct rnndb *db, const char *name) {
1355	int i;
1356	for (i = 0; i < db->spectypesnum; i++)
1357		if (!strcmp(db->spectypes[i]->name, name))
1358			return db->spectypes[i];
1359	return 0;
1360}
1361