freedreno: slurp in rnn
authorRob Clark <robdclark@chromium.org>
Thu, 23 Jul 2020 23:51:43 +0000 (16:51 -0700)
committerMarge Bot <eric+marge@anholt.net>
Tue, 28 Jul 2020 09:45:08 +0000 (09:45 +0000)
Signed-off-by: Rob Clark <robdclark@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6070>

13 files changed:
src/freedreno/meson.build
src/freedreno/rnn/aprintf.c [new file with mode: 0644]
src/freedreno/rnn/colors.c [new file with mode: 0644]
src/freedreno/rnn/colors.h [new file with mode: 0644]
src/freedreno/rnn/headergen2.c [new file with mode: 0644]
src/freedreno/rnn/meson.build [new file with mode: 0644]
src/freedreno/rnn/path.c [new file with mode: 0644]
src/freedreno/rnn/rnn.c [new file with mode: 0644]
src/freedreno/rnn/rnn.h [new file with mode: 0644]
src/freedreno/rnn/rnn_path.h [new file with mode: 0644]
src/freedreno/rnn/rnndec.c [new file with mode: 0644]
src/freedreno/rnn/rnndec.h [new file with mode: 0644]
src/freedreno/rnn/util.h [new file with mode: 0644]

index 12d787fd75b84d451406dfd8f057c718c499f7c6..7b6ab5392b10d542030fa64cf84449025ab32578 100644 (file)
@@ -28,6 +28,13 @@ subdir('fdl')
 subdir('perfcntrs')
 subdir('computerator')
 
+dep_libxml2 = dependency('libxml-2.0', required: false)
+
+# Everything that depends on rnn requires (indirectly) libxml2:
+if dep_libxml2.found()
+  subdir('rnn')
+endif
+
 if with_tools.contains('drm-shim')
   subdir('drm-shim')
 endif
diff --git a/src/freedreno/rnn/aprintf.c b/src/freedreno/rnn/aprintf.c
new file mode 100644 (file)
index 0000000..b3d924f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2009-2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "util.h"
+#include <stdarg.h>
+
+char *aprintf(const char *format, ...) {
+       va_list va;
+       va_start(va, format);
+       size_t sz = vsnprintf(0, 0, format, va);
+       va_end(va);
+       char *res = malloc(sz + 1);
+       va_start(va, format);
+       vsnprintf(res, sz + 1, format, va);
+       va_end(va);
+       return res;
+}
diff --git a/src/freedreno/rnn/colors.c b/src/freedreno/rnn/colors.c
new file mode 100644 (file)
index 0000000..192c57d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "colors.h"
+
+const struct envy_colors envy_null_colors = {
+       .reset  = "",
+       .iname  = "",
+       .rname  = "",
+       .mod    = "",
+       .sym    = "",
+       .reg    = "",
+       .regsp  = "",
+       .num    = "",
+       .mem    = "",
+       .btarg  = "",
+       .ctarg  = "",
+       .bctarg = "",
+       .eval   = "",
+       .comm   = "",
+       .err    = "",
+};
+
+const struct envy_colors envy_def_colors = {
+       .reset  = "\x1b[0m",
+       .iname  = "\x1b[0;32m",
+       .rname  = "\x1b[0;32m",
+       .mod    = "\x1b[0;36m",
+       .sym    = "\x1b[0;36m",
+       .reg    = "\x1b[0;31m",
+       .regsp  = "\x1b[0;35m",
+       .num    = "\x1b[0;33m",
+       .mem    = "\x1b[0;35m",
+       .btarg  = "\x1b[0;35m",
+       .ctarg  = "\x1b[0;1;37m",
+       .bctarg = "\x1b[0;1;35m",
+       .eval   = "\x1b[0;35m",
+       .comm   = "\x1b[0;34m",
+       .err    = "\x1b[0;1;31m",
+};
diff --git a/src/freedreno/rnn/colors.h b/src/freedreno/rnn/colors.h
new file mode 100644 (file)
index 0000000..67d929d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef COLORS_H
+#define COLORS_H
+
+struct envy_colors {
+       const char *reset;
+       const char *iname;      /* instruction name */
+       const char *rname;      /* register or bitfield name */
+       const char *mod;        /* instruction modifier */
+       const char *sym;        /* auxiliary char like { , + */
+       const char *reg;        /* ISA register */
+       const char *regsp;      /* special ISA register */
+       const char *num;        /* immediate number */
+       const char *mem;        /* memory reference */
+       const char *btarg;      /* branch target */
+       const char *ctarg;      /* call target */
+       const char *bctarg;     /* branch and call target */
+       const char *eval;       /* enum value */
+       const char *comm;       /* comment */
+       const char *err;        /* error */
+};
+
+extern const struct envy_colors envy_null_colors;
+extern const struct envy_colors envy_def_colors;
+
+#endif
diff --git a/src/freedreno/rnn/headergen2.c b/src/freedreno/rnn/headergen2.c
new file mode 100644 (file)
index 0000000..34a49a0
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * Copyright (C) 2013 Rob Clark <robdclark@gmail.com>
+ * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.com>
+ * Copyright (C) 2010 Marcin Slusarz <marcin.slusarz@gmail.com>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* modified version of headergen which uses enums and inline fxns for
+ * type safety.. based on original headergen
+ */
+#define _GNU_SOURCE
+
+#include "rnn.h"
+#include "util.h"
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <time.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <assert.h>
+
+struct rnndelem **elems = NULL;
+int elemsnum = 0;
+int elemsmax = 0;
+
+char **offsetfns = NULL;
+int offsetfnsnum = 0;
+int offsetfnsmax = 0;
+
+int startcol = 64;
+
+struct fout {
+       char *name;
+       FILE *file;
+       char *guard;
+};
+
+struct fout *fouts = 0;
+int foutsnum = 0;
+int foutsmax = 0;
+
+static bool no_asserts = false;
+
+static void seekcol (FILE *f, int src, int dst) {
+       if (dst <= src)
+               fprintf (f, "\t");
+       else {
+               int n = dst/8 - src/8;
+               if (n) {
+                       while (n--)
+                               fprintf (f, "\t");
+                       n = dst&7;
+               } else
+                       n = dst-src;
+               while (n--)
+                       fprintf (f, " ");
+       }
+}
+
+static FILE *findfout (char *file) {
+       int i;
+       for (i = 0; i < foutsnum; i++)
+               if (!strcmp(fouts[i].name, file))
+                       break;
+       if (i == foutsnum) {
+               fprintf (stderr, "AIII, didn't open file %s.\n", file);
+               exit(1);
+       }
+       return fouts[i].file;
+}
+
+static void printdef (char *name, char *suf, int type, uint64_t val, char *file) {
+       FILE *dst = findfout(file);
+       int len;
+       if (suf)
+               fprintf (dst, "#define %s__%s%n", name, suf, &len);
+       else
+               fprintf (dst, "#define %s%n", name, &len);
+       if (type == 0 && val > 0xffffffffull)
+               seekcol (dst, len, startcol-8);
+       else
+               seekcol (dst, len, startcol);
+       switch (type) {
+               case 0:
+                       if (val > 0xffffffffull)
+                               fprintf (dst, "0x%016"PRIx64"ULL\n", val);
+                       else
+                               fprintf (dst, "0x%08"PRIx64"\n", val);
+                       break;
+               case 1:
+                       fprintf (dst, "%"PRIu64"\n", val);
+                       break;
+       }
+}
+
+static void printvalue (struct rnnvalue *val, int shift) {
+       if (val->varinfo.dead)
+               return;
+       if (val->valvalid)
+               printdef (val->fullname, 0, 0, val->value << shift, val->file);
+}
+
+static void printbitfield (struct rnnbitfield *bf, int shift);
+
+static void printtypeinfo (struct rnntypeinfo *ti, struct rnnbitfield *bf,
+               char *prefix, char *file) {
+       FILE *dst = findfout(file);
+       enum rnnttype intype = ti->type;
+       char *typename = NULL;
+       uint32_t mask = typeinfo_mask(ti);
+       uint32_t width = 1 + ti->high - ti->low;
+
+       /* for fixed point, input type (arg to fxn) is float: */
+       if ((ti->type == RNN_TTYPE_FIXED) || (ti->type == RNN_TTYPE_UFIXED))
+               intype = RNN_TTYPE_FLOAT;
+
+       /* for toplevel register (ie. not bitfield), only generate accessor
+        * fxn for special cases (float, shr, min/max, etc):
+        */
+       if (bf || ti->shr || ti->minvalid || ti->maxvalid || ti->alignvalid ||
+                       ti->radixvalid || (intype == RNN_TTYPE_FLOAT)) {
+               switch (intype) {
+               case RNN_TTYPE_HEX:
+               case RNN_TTYPE_UINT:
+               case RNN_TTYPE_A3XX_REGID:
+                       typename = "uint32_t";
+                       break;
+               case RNN_TTYPE_INT:
+                       typename = "int32_t";
+                       break;
+               case RNN_TTYPE_FLOAT:
+                       typename = "float";
+                       break;
+               case RNN_TTYPE_ENUM:
+                       asprintf(&typename, "enum %s", ti->name);
+                       break;
+               }
+       }
+
+       /* for boolean, just generate a #define flag.. rather than inline fxn */
+       if (bf && (intype == RNN_TTYPE_BOOLEAN)) {
+               printdef(bf->fullname, 0, 0, mask, file);
+               return;
+       }
+
+       if (typename) {
+               printdef(prefix, "MASK", 0, mask, file);
+               printdef(prefix, "SHIFT", 1, ti->low, file);
+
+               fprintf(dst, "static inline uint32_t %s(%s val)\n", prefix, typename);
+               fprintf(dst, "{\n");
+
+               if ((ti->minvalid || ti->maxvalid || ti->alignvalid) && !no_asserts) {
+                       fprintf(dst, "\tassert(1");
+                       if (ti->minvalid)
+                               fprintf(dst, " && (val >= %lu)", ti->min);
+                       if (ti->maxvalid)
+                               fprintf(dst, " && (val <= %lu)", ti->max);
+                       if (ti->alignvalid)
+                               fprintf(dst, " && !(val %% %lu)", ti->align);
+                       fprintf(dst, ");\n");
+               }
+
+               if (ti->shr && !no_asserts) {
+                       fprintf(dst, "\tassert(!(val & 0x%x));\n", (1 << ti->shr) - 1);
+               }
+
+               fprintf(dst, "\treturn ((");
+
+               if (ti->type == RNN_TTYPE_FIXED) {
+                       fprintf(dst, "((int32_t)(val * %d.0))", (1 << ti->radix));
+               } else if (ti->type == RNN_TTYPE_UFIXED) {
+                       fprintf(dst, "((uint32_t)(val * %d.0))", (1 << ti->radix));
+               } else if (ti->type == RNN_TTYPE_FLOAT) {
+                       if (width == 32)
+                               fprintf(dst, "fui(val)");
+                       else if (width == 16)
+                               fprintf(dst, "util_float_to_half(val)");
+                       else
+                               assert(!"invalid float size");
+               } else {
+                       fprintf(dst, "val");
+               }
+
+               if (ti->shr)
+                       fprintf(dst, " >> %d", ti->shr);
+
+               fprintf(dst, ") << %s__SHIFT) & %s__MASK;\n", prefix, prefix);
+               fprintf(dst, "}\n");
+
+               if (intype == RNN_TTYPE_ENUM)
+                       free(typename);
+       }
+
+       int i;
+       for (i = 0; i < ti->valsnum; i++)
+               printvalue(ti->vals[i], ti->low);
+       for (i = 0; i < ti->bitfieldsnum; i++)
+               printbitfield(ti->bitfields[i], ti->low);
+}
+
+static void printbitfield (struct rnnbitfield *bf, int shift) {
+       if (bf->varinfo.dead)
+               return;
+       printtypeinfo (&bf->typeinfo, bf, bf->fullname, bf->file);
+}
+
+static void printdelem (struct rnndelem *elem, uint64_t offset) {
+       int use_offset_fxn;
+       char *offsetfn = NULL;
+
+       if (elem->varinfo.dead)
+               return;
+
+       use_offset_fxn = elem->offsets || elem->doffset || elem->doffsets;
+       assert((!!elem->offsets + !!elem->doffset + !!elem->doffsets) <= 1);
+
+       if (use_offset_fxn)
+               asprintf(&offsetfn, "__offset_%s", elem->name);
+
+       if (elem->length != 1) {
+               ADDARRAY(elems, elem);
+               ADDARRAY(offsetfns, offsetfn);
+       }
+
+       if (elem->name) {
+               char *regname;
+               asprintf(&regname, "REG_%s", elem->fullname);
+               if (elemsnum) {
+                       int len;
+                       FILE *dst = findfout(elem->file);
+                       int i;
+
+                       if (use_offset_fxn) {
+                               fprintf(dst, "static inline uint32_t %s(", offsetfn);
+                               if (elem->index)
+                                       fprintf(dst, "enum %s", elem->index->name);
+                               else
+                                       fprintf(dst, "uint32_t");
+                               fprintf(dst, " idx)\n");
+                               fprintf(dst, "{\n");
+                               if (elem->doffset) {
+                                       fprintf(dst, "\treturn (%s) + (%#" PRIx64 "*idx);\n", elem->doffset, elem->stride);
+                               } else {
+                                       int valuesnum = elem->doffsets ? elem->doffsetsnum : elem->offsetsnum;
+
+                                       fprintf(dst, "\tswitch (idx) {\n");
+                                       for (i = 0; i < valuesnum; i++) {
+                                               struct rnnvalue *val = NULL;
+                                               fprintf(dst, "\t\tcase ");
+                                               if (elem->index) {
+                                                       int j;
+                                                       for (j = 0; j < elem->index->valsnum; j++) {
+                                                               if (elem->index->vals[j]->value == i) {
+                                                                       val = elem->index->vals[j];
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                               if (val) {
+                                                       fprintf(dst, "%s", val->name);
+                                               } else {
+                                                       fprintf(dst, "%d", i);
+                                               }
+                                               if (elem->offsets) {
+                                                       fprintf(dst, ": return 0x%08lx;\n", elem->offsets[i]);
+                                               } else {
+                                                       fprintf(dst, ": return (%s);\n", elem->doffsets[i]);
+                                               }
+                                       }
+                                       fprintf(dst, "\t\tdefault: return INVALID_IDX(idx);\n");
+                                       fprintf(dst, "\t}\n");
+                               }
+                               fprintf(dst, "}\n");
+                       }
+                       fprintf (dst, "static inline uint32_t %s(", regname);
+                       for (i = 0; i < elemsnum; i++) {
+                               if (i)
+                                       fprintf(dst, ", ");
+                               if (elems[i]->index)
+                                       fprintf(dst, "enum %s ", elems[i]->index->name);
+                               else
+                                       fprintf(dst, "uint32_t ");
+                               fprintf (dst, "i%d%n", i, &len);
+                       }
+                       fprintf (dst, ") { return ");
+                       fprintf (dst, "0x%08"PRIx64"", offset + elem->offset);
+                       for (i = 0; i < elemsnum; i++) {
+                               if (offsetfns[i])
+                                       fprintf(dst, " + %s(i%d)", offsetfns[i], i);
+                               else
+                                       fprintf (dst, " + %#" PRIx64 "*i%d", elems[i]->stride, i);
+                       }
+                       fprintf (dst, "; }\n");
+               } else
+                       printdef (regname, 0, 0, offset + elem->offset, elem->file);
+
+               free(regname);
+/*
+               if (elem->stride)
+                       printdef (elem->fullname, "ESIZE", 0, elem->stride, elem->file);
+               if (elem->length != 1)
+                       printdef (elem->fullname, "LEN", 0, elem->length, elem->file);
+*/
+               printtypeinfo (&elem->typeinfo, NULL, elem->fullname, elem->file);
+       }
+       fprintf (findfout(elem->file), "\n");
+       int j;
+       for (j = 0; j < elem->subelemsnum; j++) {
+               printdelem(elem->subelems[j], offset + elem->offset);
+       }
+       if (elem->length != 1) {
+               elemsnum--;
+               offsetfnsnum--;
+       }
+       free(offsetfn);
+}
+
+static void print_file_info_(FILE *dst, struct stat* sb, struct tm* tm)
+{
+       char timestr[64];
+       strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
+       fprintf(dst, "(%7Lu bytes, from %s)\n", (unsigned long long)sb->st_size, timestr);
+}
+
+static void print_file_info(FILE *dst, const char* file)
+{
+       struct stat sb;
+       struct tm tm;
+       stat(file, &sb);
+       gmtime_r(&sb.st_mtime, &tm);
+       print_file_info_(dst, &sb, &tm);
+}
+
+static void printhead(struct fout f, struct rnndb *db) {
+       int i, j;
+       struct stat sb;
+       struct tm tm;
+       stat(f.name, &sb);
+       gmtime_r(&sb.st_mtime, &tm);
+       fprintf (f.file, "#ifndef %s\n", f.guard);
+       fprintf (f.file, "#define %s\n", f.guard);
+       fprintf (f.file, "\n");
+       fprintf(f.file,
+               "/* Autogenerated file, DO NOT EDIT manually!\n"
+               "\n"
+               "This file was generated by the rules-ng-ng headergen tool in this git repository:\n"
+               "http://github.com/freedreno/envytools/\n"
+               "git clone https://github.com/freedreno/envytools.git\n"
+               "\n"
+               "The rules-ng-ng source files this header was generated from are:\n");
+       unsigned maxlen = 0;
+       for(i = 0; i < db->filesnum; ++i) {
+               unsigned len = strlen(db->files[i]);
+               if(len > maxlen)
+                       maxlen = len;
+       }
+       for(i = 0; i < db->filesnum; ++i) {
+               unsigned len = strlen(db->files[i]);
+               fprintf(f.file, "- %s%*s ", db->files[i], maxlen - len, "");
+               print_file_info(f.file, db->files[i]);
+       }
+       fprintf(f.file,
+               "\n"
+               "Copyright (C) ");
+       if(db->copyright.firstyear && db->copyright.firstyear < (1900 + tm.tm_year))
+               fprintf(f.file, "%u-", db->copyright.firstyear);
+       fprintf(f.file, "%u", 1900 + tm.tm_year);
+       if(db->copyright.authorsnum) {
+               fprintf(f.file, " by the following authors:");
+               for(i = 0; i < db->copyright.authorsnum; ++i) {
+                       fprintf(f.file, "\n- ");
+                       if(db->copyright.authors[i]->name)
+                               fprintf(f.file, "%s", db->copyright.authors[i]->name);
+                       if(db->copyright.authors[i]->email)
+                               fprintf(f.file, " <%s>", db->copyright.authors[i]->email);
+                       if(db->copyright.authors[i]->nicknamesnum) {
+                               for(j = 0; j < db->copyright.authors[i]->nicknamesnum; ++j) {
+                                       fprintf(f.file, "%s%s", (j ? ", " : " ("), db->copyright.authors[i]->nicknames[j]);
+                               }
+                               fprintf(f.file, ")");
+                       }
+               }
+       }
+       fprintf(f.file, "\n");
+       if(db->copyright.license)
+               fprintf(f.file, "\n%s\n", db->copyright.license);
+       fprintf(f.file, "*/\n\n\n");
+}
+
+int main(int argc, char **argv) {
+       char *file;
+       struct rnndb *db;
+       int i, j;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage:\n\theadergen database-file\n");
+               exit(1);
+       }
+
+       if ((argc >= 3) && !strcmp(argv[1], "--no-asserts")) {
+               no_asserts = true;
+               file = argv[2];
+       } else {
+               file = argv[1];
+       }
+
+       rnn_init();
+       db = rnn_newdb();
+       rnn_parsefile (db, file);
+       rnn_prepdb (db);
+       for(i = 0; i < db->filesnum; ++i) {
+               char *dstname = malloc(strlen(db->files[i]) + 3);
+               char *pretty;
+               strcpy(dstname, db->files[i]);
+               strcat(dstname, ".h");
+               struct fout f = { db->files[i], fopen(dstname, "w") };
+               if (!f.file) {
+                       perror(dstname);
+                       exit(1);
+               }
+               free(dstname);
+               pretty = strrchr(f.name, '/');
+               if (pretty)
+                       pretty += 1;
+               else
+                       pretty = f.name;
+               f.guard = strdup(pretty);
+               for (j = 0; j < strlen(f.guard); j++)
+                       if (isalnum(f.guard[j]))
+                               f.guard[j] = toupper(f.guard[j]);
+                       else
+                               f.guard[j] = '_';
+               ADDARRAY(fouts, f);
+               printhead(f, db);
+       }
+
+       for (i = 0; i < db->enumsnum; i++) {
+               FILE *dst = NULL;
+               int j;
+               for (j = 0; j < db->enums[i]->valsnum; j++) {
+                       if (!dst) {
+                               dst = findfout(db->enums[i]->vals[j]->file);
+                               fprintf(dst, "enum %s {\n", db->enums[i]->name);
+                       }
+                       if (0xffff0000 & db->enums[i]->vals[j]->value)
+                               fprintf(dst, "\t%s = 0x%08lx,\n", db->enums[i]->vals[j]->name,
+                                               db->enums[i]->vals[j]->value);
+                       else
+                               fprintf(dst, "\t%s = %lu,\n", db->enums[i]->vals[j]->name,
+                                               db->enums[i]->vals[j]->value);
+               }
+               if (dst) {
+                       fprintf(dst, "};\n\n");
+               }
+       }
+       for (i = 0; i < db->bitsetsnum; i++) {
+               if (db->bitsets[i]->isinline)
+                       continue;
+               int j;
+               for (j = 0; j < db->bitsets[i]->bitfieldsnum; j++)
+                       printbitfield (db->bitsets[i]->bitfields[j], 0);
+       }
+       for (i = 0; i < db->domainsnum; i++) {
+               if (db->domains[i]->size)
+                       printdef (db->domains[i]->fullname, "SIZE", 0, db->domains[i]->size, db->domains[i]->file);
+               int j;
+               for (j = 0; j < db->domains[i]->subelemsnum; j++) {
+                       printdelem(db->domains[i]->subelems[j], 0);
+               }
+       }
+       for(i = 0; i < foutsnum; ++i) {
+               fprintf (fouts[i].file, "\n#endif /* %s */\n", fouts[i].guard);
+       }
+       return db->estatus;
+}
diff --git a/src/freedreno/rnn/meson.build b/src/freedreno/rnn/meson.build
new file mode 100644 (file)
index 0000000..43f7bfc
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright © 2020 Google, Inc
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+libfreedreno_rnn_files = files(
+  'aprintf.c',
+  'colors.c',
+  'colors.h',
+  'path.c',
+  'rnn.c',
+  'rnn.h',
+  'rnndec.c',
+  'rnndec.h',
+  'rnn_path.h',
+  'util.h',
+)
+
+libfreedreno_rnn = static_library(
+  'freedreno_rnn',
+  libfreedreno_rnn_files,
+  include_directories: [],
+  c_args : [
+    no_override_init_args,
+    '-DSOURCE_DIR="' + meson.source_root() + '"',
+# TODO how do we get install prefix??
+    '-DINSTALL_DIR=""',
+  ],
+  gnu_symbol_visibility: 'hidden',
+  dependencies: [ dep_libxml2 ],
+  build_by_default: false,
+)
+
+headergen2 = executable(
+  'headergen2',
+  'headergen2.c',
+  include_directories: [],
+  c_args : [no_override_init_args],
+  gnu_symbol_visibility: 'hidden',
+  dependencies: [],
+  link_with: libfreedreno_rnn,
+  build_by_default: with_tools.contains('freedreno'),
+  install: false
+)
diff --git a/src/freedreno/rnn/path.c b/src/freedreno/rnn/path.c
new file mode 100644 (file)
index 0000000..7b89a04
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "util.h"
+#include <string.h>
+
+FILE *find_in_path(const char *name, const char *path, char **pfullname) {
+       if (!path)
+               return 0;
+       while (path) {
+               const char *npath = strchr(path, ':');
+               size_t plen;
+               if (npath) {
+                       plen = npath - path;
+                       npath++;
+               } else {
+                       plen = strlen(path);
+               }
+               if (plen) {
+                       char *fullname = malloc(strlen(name) + plen + 2);
+                       strncpy(fullname, path, plen);
+                       fullname[plen] = '/';
+                       fullname[plen+1] = 0;
+                       strcat(fullname, name);
+                       FILE *file = fopen(fullname, "r");
+                       if (file) {
+                               if (pfullname)
+                                       *pfullname = fullname;
+                               else
+                                       free(fullname);
+                               return file;
+                       }
+                       free(fullname);
+               }
+               path = npath;
+       }
+       return 0;
+}
diff --git a/src/freedreno/rnn/rnn.c b/src/freedreno/rnn/rnn.c
new file mode 100644 (file)
index 0000000..3027288
--- /dev/null
@@ -0,0 +1,1332 @@
+/*
+ * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.com>
+ * Copyright (C) 2010 Francisco Jerez <currojerez@riseup.net>
+ * Copyright (C) 2010 Martin Peres <martin.peres@ensi-bourges.fr>
+ * Copyright (C) 2010 Marcin Slusarz <marcin.slusarz@gmail.com>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <libxml/xmlversion.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xmlreader.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <stdio.h>
+#include "rnn.h"
+#include "rnn_path.h"
+#include "util.h"
+
+static char *catstr (char *a, char *b) {
+       if (!a)
+               return b;
+       return aprintf("%s_%s", a, b);
+}
+
+static int strdiff (const char *a, const char *b) {
+       if (!a && !b)
+               return 0;
+       if (!a || !b)
+               return 1;
+       return strcmp (a, b);
+}
+
+void rnn_init(void) {
+       LIBXML_TEST_VERSION
+       xmlInitParser();
+}
+
+struct rnndb *rnn_newdb(void) {
+       struct rnndb *db = calloc(sizeof *db, 1);
+       return db;
+}
+
+static char *getcontent (xmlNode *attr) {
+       xmlNode *chain = attr->children;
+       size_t size = 0;
+       char *content, *p;
+       while (chain) {
+               if (chain->type == XML_TEXT_NODE)
+                       size += strlen(chain->content);
+               chain = chain->next;
+       }
+       p = content = malloc(size + 1);
+       chain = attr->children;
+       while (chain) {
+               if (chain->type == XML_TEXT_NODE) {
+                       char* sp = chain->content;
+                       if(p == content) {
+                               while(isspace(*sp))
+                                       ++sp;
+                       }
+                       size_t len = strlen(sp);
+                       memcpy(p, sp, len);
+                       p += len;
+               }
+               chain = chain->next;
+       }
+       while(p != content && isspace(p[-1]))
+               --p;
+       *p = 0;
+       return content;
+}
+
+static char *getattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
+       xmlNode *chain = attr->children;
+       while (chain) {
+               if (chain->type != XML_TEXT_NODE) {
+                       fprintf (stderr, "%s:%d: unknown attribute child \"%s\" in attribute \"%s\"\n", file, line, chain->name, attr->name);
+                       db->estatus = 1;
+               } else {
+                       return chain->content;
+               }
+               chain = chain->next;
+       }
+       return "";
+}
+
+static int getboolattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
+       char *c = getattrib(db, file, line, attr);
+       if (!strcmp(c, "yes") || !strcmp(c, "1"))
+               return 1;
+       if (!strcmp(c, "no") || !strcmp(c, "0"))
+               return 0;
+       fprintf (stderr, "%s:%d: invalid boolean value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
+       db->estatus = 1;
+       return 0;
+}
+
+static uint64_t getnum(struct rnndb *db, char *file, int line, xmlAttr *attr, char *c)
+{
+       char *cc;
+       uint64_t res;
+       if (strchr(c, 'x') || strchr(c, 'X'))
+               res = strtoull(c, &cc, 16);
+       else
+               res = strtoull(c, &cc, 10);
+       if (*cc)  {
+               fprintf (stderr, "%s:%d: invalid numeric value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
+               db->estatus = 1;
+       }
+       return res;
+}
+
+static uint64_t getnumattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
+       char *c = getattrib(db, file, line, attr);
+       return getnum(db, file, line, attr, c);
+}
+
+static int trytop (struct rnndb *db, char *file, xmlNode *node);
+
+static int trydoc (struct rnndb *db, char *file, xmlNode *node) {
+       if (!strcmp(node->name, "brief")) {
+               return 1;
+       } else if (!strcmp(node->name, "doc")) {
+               return 1;
+       }
+       return 0;
+}
+
+static struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node);
+static struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *node);
+
+static int trytypetag (struct rnndb *db, char *file, xmlNode *node, struct rnntypeinfo *ti) {
+       if (!strcmp(node->name, "value")) {
+               struct rnnvalue *val = parsevalue(db, file, node);
+               if (val)
+                       ADDARRAY(ti->vals, val);
+               return 1;
+       } else if (!strcmp(node->name, "bitfield")) {
+               struct rnnbitfield *bf = parsebitfield(db, file, node);
+               if (bf)
+                       ADDARRAY(ti->bitfields, bf);
+               return 1;
+       }
+       return 0;
+}
+static int trytypeattr (struct rnndb *db, char *file, xmlNode *node, xmlAttr *attr, struct rnntypeinfo *ti) {
+       if (!strcmp(attr->name, "shr")) {
+               ti->shr = getnumattrib(db, file, node->line, attr);
+               return 1;
+       } else if (!strcmp(attr->name, "min")) {
+               ti->min = getnumattrib(db, file, node->line, attr);
+               ti->minvalid = 1;
+               return 1;
+       } else if (!strcmp(attr->name, "max")) {
+               ti->max = getnumattrib(db, file, node->line, attr);
+               ti->maxvalid = 1;
+               return 1;
+       } else if (!strcmp(attr->name, "align")) {
+               ti->align = getnumattrib(db, file, node->line, attr);
+               ti->alignvalid = 1;
+               return 1;
+       } else if (!strcmp(attr->name, "type")) {
+               ti->name = strdup(getattrib(db, file, node->line, attr));;
+               return 1;
+       } else if (!strcmp(attr->name, "radix")) {
+               ti->radix = getnumattrib(db, file, node->line, attr);
+               ti->radixvalid = 1;
+               return 1;
+       } else if (!strcmp(attr->name, "pos")) {
+               ti->high = ti->low = getnumattrib(db, file, node->line, attr);
+               return 1;
+       } else if (!strcmp(attr->name, "low")) {
+               ti->low = getnumattrib(db, file, node->line, attr);
+               return 1;
+       } else if (!strcmp(attr->name, "high")) {
+               ti->high = getnumattrib(db, file, node->line, attr);
+               return 1;
+       } else if (!strcmp(attr->name, "addvariant")) {
+               ti->addvariant = getboolattrib(db, file, node->line, attr);
+       }
+       return 0;
+}
+
+static struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node) {
+       struct rnnvalue *val = calloc(sizeof *val, 1);
+       val->file = file;
+       xmlAttr *attr = node->properties;
+       while (attr) {
+               if (!strcmp(attr->name, "name")) {
+                       val->name = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "value")) {
+                       val->value = getnumattrib(db, file, node->line, attr);
+                       val->valvalid = 1;
+               } else if (!strcmp(attr->name, "varset")) {
+                       val->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "variants")) {
+                       val->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
+               } else {
+                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for value\n", file, node->line, attr->name);
+                       db->estatus = 1;
+               }
+               attr = attr->next;
+       }
+       xmlNode *chain = node->children;
+       while (chain) {
+               if (chain->type != XML_ELEMENT_NODE) {
+               } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
+                       fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
+                       db->estatus = 1;
+               }
+               chain = chain->next;
+       }
+       if (!val->name) {
+               fprintf (stderr, "%s:%d: nameless value\n", file, node->line);
+               db->estatus = 1;
+               return 0;
+       } else {
+               return val;
+       }
+}
+
+static void parsespectype(struct rnndb *db, char *file, xmlNode *node) {
+       struct rnnspectype *res = calloc (sizeof *res, 1);
+       res->file = file;
+       xmlAttr *attr = node->properties;
+       int i;
+       while (attr) {
+               if (!strcmp(attr->name, "name")) {
+                       res->name = strdup(getattrib(db, file, node->line, attr));
+               } else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
+                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for spectype\n", file, node->line, attr->name);
+                       db->estatus = 1;
+               }
+               attr = attr->next;
+       }
+       if (!res->name) {
+               fprintf (stderr, "%s:%d: nameless spectype\n", file, node->line);
+               db->estatus = 1;
+               return;
+       }
+       for (i = 0; i < db->spectypesnum; i++)
+               if (!strcmp(db->spectypes[i]->name, res->name)) {
+                       fprintf (stderr, "%s:%d: duplicated spectype name %s\n", file, node->line, res->name);
+                       db->estatus = 1;
+                       return;
+               }
+       ADDARRAY(db->spectypes, res);
+       xmlNode *chain = node->children;
+       while (chain) {
+               if (chain->type != XML_ELEMENT_NODE) {
+               } else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
+                       fprintf (stderr, "%s:%d: wrong tag in spectype: <%s>\n", file, chain->line, chain->name);
+                       db->estatus = 1;
+               }
+               chain = chain->next;
+       }
+}
+
+static void parseenum(struct rnndb *db, char *file, xmlNode *node) {
+       xmlAttr *attr = node->properties;
+       char *name = 0;
+       int isinline = 0;
+       int bare = 0;
+       char *prefixstr = 0;
+       char *varsetstr = 0;
+       char *variantsstr = 0;
+       int i;
+       while (attr) {
+               if (!strcmp(attr->name, "name")) {
+                       name = getattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "bare")) {
+                       bare = getboolattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "inline")) {
+                       isinline = getboolattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "prefix")) {
+                       prefixstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "varset")) {
+                       varsetstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "variants")) {
+                       variantsstr = strdup(getattrib(db, file, node->line, attr));
+               } else {
+                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for enum\n", file, node->line, attr->name);
+                       db->estatus = 1;
+               }
+               attr = attr->next;
+       }
+       if (!name) {
+               fprintf (stderr, "%s:%d: nameless enum\n", file, node->line);
+               db->estatus = 1;
+               return;
+       }
+       struct rnnenum *cur = 0;
+       for (i = 0; i < db->enumsnum; i++)
+               if (!strcmp(db->enums[i]->name, name)) {
+                       cur = db->enums[i];
+                       break;
+               }
+       if (cur) {
+               if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
+                               strdiff(cur->varinfo.varsetstr, varsetstr) ||
+                               strdiff(cur->varinfo.variantsstr, variantsstr) ||
+                               cur->isinline != isinline || cur->bare != bare) {
+                       fprintf (stderr, "%s:%d: merge fail for enum %s\n", file, node->line, node->name);
+                       db->estatus = 1;
+               }
+       } else {
+               cur = calloc(sizeof *cur, 1);
+               cur->name = strdup(name);
+               cur->isinline = isinline;
+               cur->bare = bare;
+               cur->varinfo.prefixstr = prefixstr;
+               cur->varinfo.varsetstr = varsetstr;
+               cur->varinfo.variantsstr = variantsstr;
+               cur->file = file;
+               ADDARRAY(db->enums, cur);
+       }
+       xmlNode *chain = node->children;
+       while (chain) {
+               if (chain->type != XML_ELEMENT_NODE) {
+               } else if (!strcmp(chain->name, "value")) {
+                       struct rnnvalue *val = parsevalue(db, file, chain);
+                       if (val)
+                               ADDARRAY(cur->vals, val);
+               } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
+                       fprintf (stderr, "%s:%d: wrong tag in enum: <%s>\n", file, chain->line, chain->name);
+                       db->estatus = 1;
+               }
+               chain = chain->next;
+       }
+}
+
+static struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *node) {
+       struct rnnbitfield *bf = calloc(sizeof *bf, 1);
+       bf->file = file;
+       xmlAttr *attr = node->properties;
+       bf->typeinfo.low = bf->typeinfo.high = -1;
+       while (attr) {
+               if (!strcmp(attr->name, "name")) {
+                       bf->name = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "varset")) {
+                       bf->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "variants")) {
+                       bf->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!trytypeattr(db, file, node, attr, &bf->typeinfo)) {
+                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for bitfield\n", file, node->line, attr->name);
+                       db->estatus = 1;
+               }
+               attr = attr->next;
+       }
+       xmlNode *chain = node->children;
+       while (chain) {
+               if (chain->type != XML_ELEMENT_NODE) {
+               } else if (!trytypetag(db, file, chain, &bf->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
+                       fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
+                       db->estatus = 1;
+               }
+               chain = chain->next;
+       }
+       if (!bf->name) {
+               fprintf (stderr, "%s:%d: nameless bitfield\n", file, node->line);
+               db->estatus = 1;
+               return 0;
+       } else if (bf->typeinfo.low < 0|| bf->typeinfo.high < 0 || bf->typeinfo.high < bf->typeinfo.low) {
+               fprintf (stderr, "%s:%d: bitfield has wrong placement\n", file, node->line);
+               db->estatus = 1;
+               return 0;
+       } else {
+               return bf;
+       }
+}
+
+static void parsebitset(struct rnndb *db, char *file, xmlNode *node) {
+       xmlAttr *attr = node->properties;
+       char *name = 0;
+       int isinline = 0;
+       int bare = 0;
+       char *prefixstr = 0;
+       char *varsetstr = 0;
+       char *variantsstr = 0;
+       int i;
+       while (attr) {
+               if (!strcmp(attr->name, "name")) {
+                       name = getattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "bare")) {
+                       bare = getboolattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "inline")) {
+                       isinline = getboolattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "prefix")) {
+                       prefixstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "varset")) {
+                       varsetstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "variants")) {
+                       variantsstr = strdup(getattrib(db, file, node->line, attr));
+               } else {
+                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for bitset\n", file, node->line, attr->name);
+                       db->estatus = 1;
+               }
+               attr = attr->next;
+       }
+       if (!name) {
+               fprintf (stderr, "%s:%d: nameless bitset\n", file, node->line);
+               db->estatus = 1;
+               return;
+       }
+       struct rnnbitset *cur = 0;
+       for (i = 0; i < db->bitsetsnum; i++)
+               if (!strcmp(db->bitsets[i]->name, name)) {
+                       cur = db->bitsets[i];
+                       break;
+               }
+       if (cur) {
+               if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
+                               strdiff(cur->varinfo.varsetstr, varsetstr) ||
+                               strdiff(cur->varinfo.variantsstr, variantsstr) ||
+                               cur->isinline != isinline || cur->bare != bare) {
+                       fprintf (stderr, "%s:%d: merge fail for bitset %s\n", file, node->line, node->name);
+                       db->estatus = 1;
+               }
+       } else {
+               cur = calloc(sizeof *cur, 1);
+               cur->name = strdup(name);
+               cur->isinline = isinline;
+               cur->bare = bare;
+               cur->varinfo.prefixstr = prefixstr;
+               cur->varinfo.varsetstr = varsetstr;
+               cur->varinfo.variantsstr = variantsstr;
+               cur->file = file;
+               ADDARRAY(db->bitsets, cur);
+       }
+       xmlNode *chain = node->children;
+       while (chain) {
+               if (chain->type != XML_ELEMENT_NODE) {
+               } else if (!strcmp(chain->name, "bitfield")) {
+                       struct rnnbitfield *bf = parsebitfield(db, file, chain);
+                       if (bf)
+                               ADDARRAY(cur->bitfields, bf);
+               } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
+                       fprintf (stderr, "%s:%d: wrong tag in bitset: <%s>\n", file, chain->line, chain->name);
+                       db->estatus = 1;
+               }
+               chain = chain->next;
+       }
+}
+
+static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
+       if (!strcmp(node->name, "use-group")) {
+               struct rnndelem *res = calloc(sizeof *res, 1);
+               res->file = file;
+               res->type = RNN_ETYPE_USE_GROUP;
+               xmlAttr *attr = node->properties;
+               while (attr) {
+                       if (!strcmp(attr->name, "name")) {
+                               res->name = strdup(getattrib(db, file, node->line, attr));
+                       } else {
+                               fprintf (stderr, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
+                               db->estatus = 1;
+                       }
+                       attr = attr->next;
+               }
+               if (!res->name) {
+                       fprintf (stderr, "%s:%d: nameless use-group\n", file, node->line);
+                       db->estatus = 1;
+                       return 0;
+               }
+               return res;
+       } else if (!strcmp(node->name, "stripe") || !strcmp(node->name, "array")) {
+               struct rnndelem *res = calloc(sizeof *res, 1);
+               res->type = (strcmp(node->name, "stripe")?RNN_ETYPE_ARRAY:RNN_ETYPE_STRIPE);
+               res->length = 1;
+               res->file = file;
+               xmlAttr *attr = node->properties;
+               while (attr) {
+                       if (!strcmp(attr->name, "name")) {
+                               res->name = strdup(getattrib(db, file, node->line, attr));
+                       } else if (!strcmp(attr->name, "offset")) {
+                               res->offset = getnumattrib(db, file, node->line, attr);
+                       } else if (!strcmp(attr->name, "offsets")) {
+                               char *str = strdup(getattrib(db, file, node->line, attr));
+                               char *tok, *save, *tmp = str;
+                               while ((tok = strtok_r(str, ",", &save))) {
+                                       uint64_t offset = getnum(db, file, node->line, attr, tok);
+                                       ADDARRAY(res->offsets, offset);
+                                       str = NULL;
+                               }
+                               if (str)
+                                       fprintf(stderr, "%s:%d: invalid offsets: %s\n", file, node->line, str);
+                               free(tmp);
+                       } else if (!strcmp(attr->name, "doffset")) {
+                               /* dynamic runtime determined offset: */
+                               res->doffset = strdup(getattrib(db, file, node->line, attr));
+                       } else if (!strcmp(attr->name, "doffsets")) {
+                               /* dynamic runtime determined offsets: */
+                               char *str = strdup(getattrib(db, file, node->line, attr));
+                               char *tok, *save, *tmp = str;
+                               while ((tok = strtok_r(str, ",", &save))) {
+                                       char *doffset = strdup(tok);
+                                       ADDARRAY(res->doffsets, doffset);
+                                       str = NULL;
+                               }
+                               if (str)
+                                       fprintf(stderr, "%s:%d: invalid offsets: %s\n", file, node->line, str);
+                               free(tmp);
+                       } else if (!strcmp(attr->name, "length")) {
+                               res->length = getnumattrib(db, file, node->line, attr);
+                       } else if (!strcmp(attr->name, "stride")) {
+                               res->stride = getnumattrib(db, file, node->line, attr);
+                       } else if (!strcmp(attr->name, "prefix")) {
+                               res->varinfo.prefixstr = strdup(getattrib(db, file, node->line, attr));
+                       } else if (!strcmp(attr->name, "varset")) {
+                               res->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
+                       } else if (!strcmp(attr->name, "variants")) {
+                               res->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
+                       } else if (!strcmp(attr->name, "index")) {
+                               const char *enumname = getattrib(db, file, node->line, attr);
+                               res->index = rnn_findenum(db, enumname);
+                               if (!res->index) {
+                                       fprintf(stderr, "%s:%d: invalid enum name \"%s\"\n", file, node->line, enumname);
+                                       db->estatus = 1;
+                               }
+                       } else {
+                               fprintf (stderr, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
+                               db->estatus = 1;
+                       }
+                       attr = attr->next;
+               }
+               xmlNode *chain = node->children;
+               while (chain) {
+                       struct rnndelem *delem;
+                       if (chain->type != XML_ELEMENT_NODE) {
+                       } else if ((delem = trydelem(db, file, chain))) {
+                               ADDARRAY(res->subelems, delem);
+                       } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
+                               fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
+                               db->estatus = 1;
+                       }
+                       chain = chain->next;
+               }
+
+               /* Sanity checking */
+               if (res->type == RNN_ETYPE_ARRAY && res->stride == 0) {
+                       fprintf(stderr, "%s: Array %s's stride is undefined. Aborting.\n", file, res->name);
+                       exit(-1);
+               }
+               return res;
+
+       }
+       int width;
+       if (!strcmp(node->name, "reg8"))
+               width = 8;
+       else if (!strcmp(node->name, "reg16"))
+               width = 16;
+       else if (!strcmp(node->name, "reg32"))
+               width = 32;
+       else if (!strcmp(node->name, "reg64"))
+               width = 64;
+       else
+               return 0;
+       struct rnndelem *res = calloc(sizeof *res, 1);
+       res->file = file;
+       res->type = RNN_ETYPE_REG;
+       res->width = width;
+       res->length = 1;
+       res->access = RNN_ACCESS_RW;
+       xmlAttr *attr = node->properties;
+       res->typeinfo.low = 0;
+       res->typeinfo.high = width - 1;
+       while (attr) {
+               if (!strcmp(attr->name, "name")) {
+                       res->name = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "offset")) {
+                       res->offset = getnumattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "length")) {
+                       res->length = getnumattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "stride")) {
+                       res->stride = getnumattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "varset")) {
+                       res->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "variants")) {
+                       res->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "access")) {
+                       char *str = getattrib(db, file, node->line, attr);
+                       if (!strcmp(str, "r"))
+                               res->access = RNN_ACCESS_R;
+                       else if (!strcmp(str, "w"))
+                               res->access = RNN_ACCESS_W;
+                       else if (!strcmp(str, "rw"))
+                               res->access = RNN_ACCESS_RW;
+                       else
+                               fprintf (stderr, "%s:%d: wrong access type \"%s\" for register\n", file, node->line, str);
+               } else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
+                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for register\n", file, node->line, attr->name);
+                       db->estatus = 1;
+               }
+               attr = attr->next;
+       }
+       xmlNode *chain = node->children;
+       while (chain) {
+               if (chain->type != XML_ELEMENT_NODE) {
+               } else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
+                       fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
+                       db->estatus = 1;
+               }
+               chain = chain->next;
+       }
+       if (!res->name) {
+               fprintf (stderr, "%s:%d: nameless register\n", file, node->line);
+               db->estatus = 1;
+               return 0;
+       } else {
+       }
+       return res;
+}
+
+static void parsegroup(struct rnndb *db, char *file, xmlNode *node) {
+       xmlAttr *attr = node->properties;
+       char *name = 0;
+       int i;
+       while (attr) {
+               if (!strcmp(attr->name, "name")) {
+                       name = getattrib(db, file, node->line, attr);
+               } else {
+                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for group\n", file, node->line, attr->name);
+                       db->estatus = 1;
+               }
+               attr = attr->next;
+       }
+       if (!name) {
+               fprintf (stderr, "%s:%d: nameless group\n", file, node->line);
+               db->estatus = 1;
+               return;
+       }
+       struct rnngroup *cur = 0;
+       for (i = 0; i < db->groupsnum; i++)
+               if (!strcmp(db->groups[i]->name, name)) {
+                       cur = db->groups[i];
+                       break;
+               }
+       if (!cur) {
+               cur = calloc(sizeof *cur, 1);
+               cur->name = strdup(name);
+               ADDARRAY(db->groups, cur);
+       }
+       xmlNode *chain = node->children;
+       while (chain) {
+               struct rnndelem *delem;
+               if (chain->type != XML_ELEMENT_NODE) {
+               } else if ((delem = trydelem(db, file, chain))) {
+                       ADDARRAY(cur->subelems, delem);
+               } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
+                       fprintf (stderr, "%s:%d: wrong tag in group: <%s>\n", file, chain->line, chain->name);
+                       db->estatus = 1;
+               }
+               chain = chain->next;
+       }
+}
+
+static void parsedomain(struct rnndb *db, char *file, xmlNode *node) {
+       xmlAttr *attr = node->properties;
+       char *name = 0;
+       uint64_t size = 0; int width = 8;
+       int bare = 0;
+       char *prefixstr = 0;
+       char *varsetstr = 0;
+       char *variantsstr = 0;
+       int i;
+       while (attr) {
+               if (!strcmp(attr->name, "name")) {
+                       name = getattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "bare")) {
+                       bare = getboolattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "size")) {
+                       size = getnumattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "width")) {
+                       width = getnumattrib(db, file, node->line, attr);
+               } else if (!strcmp(attr->name, "prefix")) {
+                       prefixstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "varset")) {
+                       varsetstr = strdup(getattrib(db, file, node->line, attr));
+               } else if (!strcmp(attr->name, "variants")) {
+                       variantsstr = strdup(getattrib(db, file, node->line, attr));
+               } else {
+                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for domain\n", file, node->line, attr->name);
+                       db->estatus = 1;
+               }
+               attr = attr->next;
+       }
+       if (!name) {
+               fprintf (stderr, "%s:%d: nameless domain\n", file, node->line);
+               db->estatus = 1;
+               return;
+       }
+       struct rnndomain *cur = 0;
+       for (i = 0; i < db->domainsnum; i++)
+               if (!strcmp(db->domains[i]->name, name)) {
+                       cur = db->domains[i];
+                       break;
+               }
+       if (cur) {
+               if (strdiff(cur->varinfo.prefixstr, prefixstr) ||
+                               strdiff(cur->varinfo.varsetstr, varsetstr) ||
+                               strdiff(cur->varinfo.variantsstr, variantsstr) ||
+                               cur->width != width ||
+                               cur->bare != bare ||
+                               (size && cur->size && size != cur->size)) {
+                       fprintf (stderr, "%s:%d: merge fail for domain %s\n", file, node->line, node->name);
+                       db->estatus = 1;
+               } else {
+                       if (size)
+                               cur->size = size;
+               }
+       } else {
+               cur = calloc(sizeof *cur, 1);
+               cur->name = strdup(name);
+               cur->bare = bare;
+               cur->width = width;
+               cur->size = size;
+               cur->varinfo.prefixstr = prefixstr;
+               cur->varinfo.varsetstr = varsetstr;
+               cur->varinfo.variantsstr = variantsstr;
+               cur->file = file;
+               ADDARRAY(db->domains, cur);
+       }
+       xmlNode *chain = node->children;
+       while (chain) {
+               struct rnndelem *delem;
+               if (chain->type != XML_ELEMENT_NODE) {
+               } else if ((delem = trydelem(db, file, chain))) {
+                       ADDARRAY(cur->subelems, delem);
+               } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
+                       fprintf (stderr, "%s:%d: wrong tag in domain: <%s>\n", file, chain->line, chain->name);
+                       db->estatus = 1;
+               }
+               chain = chain->next;
+       }
+}
+
+static void parsecopyright(struct rnndb *db, char *file, xmlNode *node) {
+       struct rnncopyright* copyright = &db->copyright;
+       xmlAttr *attr = node->properties;
+       while (attr) {
+               if (!strcmp(attr->name, "year")) {
+                       unsigned firstyear = getnumattrib(db, file, node->line, attr);
+                       if(!copyright->firstyear || firstyear < copyright->firstyear)
+                               copyright->firstyear = firstyear;
+               } else {
+                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for copyright\n", file, node->line, attr->name);
+                       db->estatus = 1;
+               }
+               attr = attr->next;
+       }
+       xmlNode *chain = node->children;
+       while (chain) {
+               if (chain->type != XML_ELEMENT_NODE) {
+               } else if (!strcmp(chain->name, "license"))
+                       if(copyright->license) {
+                               if(strcmp(copyright->license, node->content)) {
+                                       fprintf(stderr, "fatal error: multiple different licenses specified!\n");
+                                       abort(); /* TODO: do something better here, but headergen, xml2html, etc. should not produce anything in this case */
+                               }
+                       } else
+                               copyright->license = getcontent(chain);
+               else if (!strcmp(chain->name, "author")) {
+                       struct rnnauthor* author = calloc(sizeof *author, 1);
+                       xmlAttr* authorattr = chain->properties;
+                       xmlNode *authorchild = chain->children;
+                       author->contributions = getcontent(chain);
+                       while (authorattr) {
+                               if (!strcmp(authorattr->name, "name"))
+                                       author->name = strdup(getattrib(db, file, chain->line, authorattr));
+                               else if (!strcmp(authorattr->name, "email"))
+                                       author->email = strdup(getattrib(db, file, chain->line, authorattr));
+                               else {
+                                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for author\n", file, chain->line, authorattr->name);
+                                       db->estatus = 1;
+                               }
+                               authorattr = authorattr->next;
+                       }
+                       while(authorchild)  {
+                               if (authorchild->type != XML_ELEMENT_NODE) {
+                               } else if (!strcmp(authorchild->name, "nick")) {
+                                       xmlAttr* nickattr = authorchild->properties;
+                                       char* nickname = 0;
+                                       while(nickattr) {
+                                               if (!strcmp(nickattr->name, "name"))
+                                                       nickname = strdup(getattrib(db, file, authorchild->line, nickattr));
+                                               else {
+                                                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for nick\n", file, authorchild->line, nickattr->name);
+                                                       db->estatus = 1;
+                                               }
+                                               nickattr = nickattr->next;
+                                       }
+                                       if(!nickname) {
+                                               fprintf (stderr, "%s:%d: missing \"name\" attribute for nick\n", file, authorchild->line);
+                                               db->estatus = 1;
+                                       } else
+                                               ADDARRAY(author->nicknames, nickname);
+                               } else {
+                                       fprintf (stderr, "%s:%d: wrong tag in author: <%s>\n", file, authorchild->line, authorchild->name);
+                                       db->estatus = 1;
+                               }
+                               authorchild = authorchild->next;
+                       }
+                       ADDARRAY(copyright->authors, author);
+               } else {
+                       fprintf (stderr, "%s:%d: wrong tag in copyright: <%s>\n", file, chain->line, chain->name);
+                       db->estatus = 1;
+               }
+               chain = chain->next;
+       }
+}
+
+static int trytop (struct rnndb *db, char *file, xmlNode *node) {
+       if (!strcmp(node->name, "enum")) {
+               parseenum(db, file, node);
+               return 1;
+       } else if (!strcmp(node->name, "bitset")) {
+               parsebitset(db, file, node);
+               return 1;
+       } else if (!strcmp(node->name, "group")) {
+               parsegroup(db, file, node);
+               return 1;
+       } else if (!strcmp(node->name, "domain")) {
+               parsedomain(db, file, node);
+               return 1;
+       } else if (!strcmp(node->name, "spectype")) {
+               parsespectype(db, file, node);
+               return 1;
+       } else if (!strcmp(node->name, "import")) {
+               xmlAttr *attr = node->properties;
+               char *subfile = 0;
+               while (attr) {
+                       if (!strcmp(attr->name, "file")) {
+                               subfile = getattrib(db, file, node->line, attr);
+                       } else {
+                               fprintf (stderr, "%s:%d: wrong attribute \"%s\" for import\n", file, node->line, attr->name);
+                               db->estatus = 1;
+                       }
+                       attr = attr->next;
+               }
+               if (!subfile) {
+                       fprintf (stderr, "%s:%d: missing \"file\" attribute for import\n", file, node->line);
+                       db->estatus = 1;
+               } else {
+                       rnn_parsefile(db, subfile);
+               }
+               return 1;
+       } else if (!strcmp(node->name, "copyright")) {
+               parsecopyright(db, file, node);
+               return 1;
+       }
+       return 0;
+}
+
+void rnn_parsefile (struct rnndb *db, char *file_orig) {
+       int i;
+       char *fname;
+       const char *rnn_path = getenv("RNN_PATH");
+
+       if (!rnn_path)
+               rnn_path = RNN_DEF_PATH;
+
+       FILE *file = find_in_path(file_orig, rnn_path, &fname);
+       if (!file) {
+               fprintf (stderr, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", file_orig);
+               db->estatus = 1;
+               return;
+       }
+       fclose(file);
+
+       for (i = 0; i < db->filesnum; i++)
+               if (!strcmp(db->files[i], fname))
+                       return;
+               
+       ADDARRAY(db->files, fname);
+       xmlDocPtr doc = xmlParseFile(fname);
+       if (!doc) {
+               fprintf (stderr, "%s: couldn't open database file. Please set the env var RNN_PATH.\n", fname);
+               db->estatus = 1;
+               return;
+       }
+       xmlNode *root = doc->children;
+       while (root) {
+               if (root->type != XML_ELEMENT_NODE) {
+               } else if (strcmp(root->name, "database")) {
+                       fprintf (stderr, "%s:%d: wrong top-level tag <%s>\n", fname, root->line, root->name);
+                       db->estatus = 1;
+               } else {
+                       xmlNode *chain = root->children;
+                       while (chain) {
+                               if (chain->type != XML_ELEMENT_NODE) {
+                               } else if (!trytop(db, fname, chain) && !trydoc(db, fname, chain)) {
+                                       fprintf (stderr, "%s:%d: wrong tag in database: <%s>\n", fname, chain->line, chain->name);
+                                       db->estatus = 1;
+                               }
+                               chain = chain->next;
+                       }
+               }
+               root = root->next;
+       }
+       xmlFreeDoc(doc);
+}
+
+static struct rnnvalue *copyvalue (struct rnnvalue *val, char *file) {
+       struct rnnvalue *res = calloc (sizeof *res, 1);
+       res->name = val->name;
+       res->valvalid = val->valvalid;
+       res->value = val->value;
+       res->varinfo = val->varinfo;
+       res->file = file;
+       return res;
+}
+
+static struct rnnbitfield *copybitfield (struct rnnbitfield *bf, char *file);
+
+
+static void copytypeinfo (struct rnntypeinfo *dst, struct rnntypeinfo *src, char *file) {
+       int i;
+       dst->name = src->name;
+       dst->shr = src->shr;
+       dst->low = src->low;
+       dst->high = src->high;
+       dst->min = src->min;
+       dst->max = src->max;
+       dst->align = src->align;
+       dst->addvariant = src->addvariant;
+       for (i = 0; i < src->valsnum; i++)
+               ADDARRAY(dst->vals, copyvalue(src->vals[i], file));
+       for (i = 0; i < src->bitfieldsnum; i++)
+               ADDARRAY(dst->bitfields, copybitfield(src->bitfields[i], file));
+}
+
+static struct rnnbitfield *copybitfield (struct rnnbitfield *bf, char *file) {
+       struct rnnbitfield *res = calloc (sizeof *res, 1);
+       res->name = bf->name;
+       res->varinfo = bf->varinfo;
+       res->file = file;
+       copytypeinfo(&res->typeinfo, &bf->typeinfo, file);
+       return res;
+}
+
+static struct rnndelem *copydelem (struct rnndelem *elem, char *file) {
+       struct rnndelem *res = calloc (sizeof *res, 1);
+       res->type = elem->type;
+       res->name = elem->name;
+       res->width = elem->width;
+       res->access = elem->access;
+       res->offset = elem->offset;
+       res->length = elem->length;
+       res->stride = elem->stride;
+       res->varinfo = elem->varinfo;
+       res->file = file;
+       copytypeinfo(&res->typeinfo, &elem->typeinfo, file);
+       int i;
+       for (i = 0; i < elem->subelemsnum; i++)
+               ADDARRAY(res->subelems, copydelem(elem->subelems[i], file));
+       for (i = 0; i < elem->offsetsnum; i++)
+               ADDARRAY(res->offsets, elem->offsets[i]);
+       return res;
+}
+
+static struct rnnvarset *copyvarset (struct rnnvarset *varset) {
+       struct rnnvarset *res = calloc(sizeof *res, 1);
+       res->venum = varset->venum;
+       res->variants = calloc(sizeof *res->variants, res->venum->valsnum);
+       int i;
+       for (i = 0; i < res->venum->valsnum; i++)
+               res->variants[i] = varset->variants[i];
+       return res;
+}
+
+static void prepenum(struct rnndb *db, struct rnnenum *en);
+
+static int findvidx (struct rnndb *db, struct rnnenum *en, char *name) {
+       int i;
+       for (i = 0; i < en->valsnum; i++)
+               if (!strcmp(en->vals[i]->name, name))
+                       return i;
+       fprintf (stderr, "Cannot find variant %s in enum %s!\n", name, en->name);
+       db->estatus = 1;
+       return -1;
+}
+
+static void prepvarinfo (struct rnndb *db, char *what, struct rnnvarinfo *vi, struct rnnvarinfo *parent) {
+       if (parent)
+               vi->prefenum = parent->prefenum;
+       if (vi->prefixstr) {
+               if (!strcmp(vi->prefixstr, "none"))
+                       vi->prefenum = 0;
+               else
+                       vi->prefenum = rnn_findenum(db, vi->prefixstr); // XXX
+       }
+       int i;
+       if (parent)
+               for (i = 0; i < parent->varsetsnum; i++)
+                       ADDARRAY(vi->varsets, copyvarset(parent->varsets[i]));
+       struct rnnenum *varset = vi->prefenum;
+       if (!varset && !vi->varsetstr && parent)
+               vi->varsetstr = parent->varsetstr;
+       if (vi->varsetstr)
+               varset = rnn_findenum(db, vi->varsetstr);
+       if (vi->variantsstr) {
+               char *vars = vi->variantsstr;
+               if (!varset) {
+                       fprintf (stderr, "%s: tried to use variants without active varset!\n", what);
+                       db->estatus = 1;
+                       return;
+               }
+               struct rnnvarset *vs = 0;
+               int nvars = varset->valsnum;
+               for (i = 0; i < vi->varsetsnum; i++)
+                       if (vi->varsets[i]->venum == varset) {
+                               vs = vi->varsets[i];
+                               break;
+                       }
+               if (!vs) {
+                       vs = calloc (sizeof *vs, 1);
+                       vs->venum = varset;
+                       vs->variants = calloc(sizeof *vs->variants, nvars);
+                       for (i = 0; i < nvars; i++)
+                               vs->variants[i] = 1;
+                       ADDARRAY(vi->varsets, vs);
+               }
+               while (1) {
+                       while (*vars == ' ') vars++;
+                       if (*vars == 0)
+                               break;
+                       char *split = vars;
+                       while (*split != ':' && *split != '-' && *split != ' '  && *split != 0)
+                               split++;
+                       char *first = 0;
+                       if (split != vars)
+                               first = strndup(vars, split-vars);
+                       if (*split == ' ' || *split == 0) {
+                               int idx = findvidx(db, varset, first);
+                               if (idx != -1)
+                                       vs->variants[idx] |= 2;
+                               vars = split;
+                       } else {
+                               char *end = split+1;
+                               while (*end != ' '  && *end != 0)
+                                       end++;
+                               char *second = 0;
+                               if (end != split+1)
+                                       second = strndup(split+1, end-split-1);
+                               int idx1 = 0;
+                               if (first)
+                                       idx1 = findvidx(db, varset, first);
+                               int idx2 = nvars;
+                               if (second) {
+                                       idx2 = findvidx(db, varset, second);
+                                       if (*split == '-')
+                                               idx2++;
+                               }
+                               if (idx1 != -1 && idx2 != -1)
+                                       for (i = idx1; i < idx2; i++)
+                                               vs->variants[i] |= 2;
+                               vars = end;
+                               free(second);
+                       }
+                       free(first);
+               }
+               vi->dead = 1;
+               for (i = 0; i < nvars; i++) {
+                       vs->variants[i] = (vs->variants[i] == 3);
+                       if (vs->variants[i])
+                               vi->dead = 0;
+               }
+       }
+       if (vi->dead)
+               return;
+       if (vi->prefenum) {
+               struct rnnvarset *vs = 0;
+               for (i = 0; i < vi->varsetsnum; i++)
+                       if (vi->varsets[i]->venum == vi->prefenum) {
+                               vs = vi->varsets[i];
+                               break;
+                       }
+               if (vs) {
+                       for (i = 0; i < vi->prefenum->valsnum; i++)
+                               if (vs->variants[i]) {
+                                       vi->prefix = vi->prefenum->vals[i]->name;
+                                       return;
+                               }
+               } else {
+                       vi->prefix = vi->prefenum->vals[0]->name;
+               }
+       }
+}
+
+static void prepvalue(struct rnndb *db, struct rnnvalue *val, char *prefix, struct rnnvarinfo *parvi) {
+       val->fullname = catstr(prefix, val->name);
+       prepvarinfo (db, val->fullname, &val->varinfo, parvi);
+       if (val->varinfo.dead)
+               return;
+       if (val->varinfo.prefix)
+               val->fullname = catstr(val->varinfo.prefix, val->fullname);
+}
+
+static void prepbitfield(struct rnndb *db, struct rnnbitfield *bf, char *prefix, struct rnnvarinfo *parvi);
+
+static void preptypeinfo(struct rnndb *db, struct rnntypeinfo *ti, char *prefix, struct rnnvarinfo *vi, char *file) {
+       int i;
+       if (ti->name) {
+               struct rnnenum *en = rnn_findenum (db, ti->name);
+               struct rnnbitset *bs = rnn_findbitset (db, ti->name);
+               struct rnnspectype *st = rnn_findspectype (db, ti->name);
+               if (en) {
+                       if (en->isinline) {
+                               ti->type = RNN_TTYPE_INLINE_ENUM;
+                               int j;
+                               for (j = 0; j < en->valsnum; j++)
+                                       ADDARRAY(ti->vals, copyvalue(en->vals[j], file));
+                       } else {
+                               ti->type = RNN_TTYPE_ENUM;
+                               ti->eenum = en;
+                       }
+               } else if (bs) {
+                       if (bs->isinline) {
+                               ti->type = RNN_TTYPE_INLINE_BITSET;
+                               int j;
+                               for (j = 0; j < bs->bitfieldsnum; j++)
+                                       ADDARRAY(ti->bitfields, copybitfield(bs->bitfields[j], file));
+                       } else {
+                               ti->type = RNN_TTYPE_BITSET;
+                               ti->ebitset = bs;
+                       }
+               } else if (st) {
+                       ti->type = RNN_TTYPE_SPECTYPE;
+                       ti->spectype = st;
+               } else if (!strcmp(ti->name, "hex")) {
+                       ti->type = RNN_TTYPE_HEX;
+               } else if (!strcmp(ti->name, "float")) {
+                       ti->type = RNN_TTYPE_FLOAT;
+               } else if (!strcmp(ti->name, "uint")) {
+                       ti->type = RNN_TTYPE_UINT;
+               } else if (!strcmp(ti->name, "int")) {
+                       ti->type = RNN_TTYPE_INT;
+               } else if (!strcmp(ti->name, "boolean")) {
+                       ti->type = RNN_TTYPE_BOOLEAN;
+               } else if (!strcmp(ti->name, "bitfield")) {
+                       ti->type = RNN_TTYPE_INLINE_BITSET;
+               } else if (!strcmp(ti->name, "enum")) {
+                       ti->type = RNN_TTYPE_INLINE_ENUM;
+               } else if (!strcmp(ti->name, "fixed")) {
+                       ti->type = RNN_TTYPE_FIXED;
+               } else if (!strcmp(ti->name, "ufixed")) {
+                       ti->type = RNN_TTYPE_UFIXED;
+               } else if (!strcmp(ti->name, "a3xx_regid")) {
+                       ti->type = RNN_TTYPE_A3XX_REGID;
+               } else if (!strcmp(ti->name, "waddress") || !strcmp(ti->name, "address")) {
+                       ti->type = RNN_TTYPE_HEX;
+               } else {
+                       ti->type = RNN_TTYPE_HEX;
+                       fprintf (stderr, "%s: unknown type %s\n", prefix, ti->name);
+                       db->estatus = 1;
+               }
+       } else if (ti->bitfieldsnum) {
+               ti->name = "bitfield";
+               ti->type = RNN_TTYPE_INLINE_BITSET;
+       } else if (ti->valsnum) {
+               ti->name = "enum";
+               ti->type = RNN_TTYPE_INLINE_ENUM;
+       } else if (ti->low == 0 && ti->high == 0) {
+               ti->name = "boolean";
+               ti->type = RNN_TTYPE_BOOLEAN;
+       } else {
+               ti->name = "hex";
+               ti->type = RNN_TTYPE_HEX;
+       }
+       if (ti->addvariant && ti->type != RNN_TTYPE_ENUM) {
+               fprintf (stderr, "%s: addvariant specified on non-enum type %s\n", prefix, ti->name);
+               db->estatus = 1;
+       }
+       for (i = 0; i < ti->bitfieldsnum; i++)
+               prepbitfield(db,  ti->bitfields[i], prefix, vi);
+       for (i = 0; i < ti->valsnum; i++)
+               prepvalue(db, ti->vals[i], prefix, vi);
+}
+
+static void prepbitfield(struct rnndb *db, struct rnnbitfield *bf, char *prefix, struct rnnvarinfo *parvi) {
+       bf->fullname = catstr(prefix, bf->name);
+       prepvarinfo (db, bf->fullname, &bf->varinfo, parvi);
+       if (bf->varinfo.dead)
+               return;
+       preptypeinfo(db, &bf->typeinfo, bf->fullname, &bf->varinfo, bf->file);
+       if (bf->varinfo.prefix)
+               bf->fullname = catstr(bf->varinfo.prefix, bf->fullname);
+}
+
+static void prepdelem(struct rnndb *db, struct rnndelem *elem, char *prefix, struct rnnvarinfo *parvi, int width) {
+       if (elem->type == RNN_ETYPE_USE_GROUP) {
+               int i;
+               struct rnngroup *gr = 0;
+               for (i = 0; i < db->groupsnum; i++)
+                       if (!strcmp(db->groups[i]->name, elem->name)) {
+                               gr = db->groups[i];
+                               break;
+                       }
+               if (gr) {
+                       for (i = 0; i < gr->subelemsnum; i++)
+                               ADDARRAY(elem->subelems, copydelem(gr->subelems[i], elem->file));
+               } else {
+                       fprintf (stderr, "group %s not found!\n", elem->name);
+                       db->estatus = 1;
+               }
+               elem->type = RNN_ETYPE_STRIPE;
+               elem->length = 1;
+               elem->name = 0;
+       }
+       if (elem->name)
+               elem->fullname = catstr(prefix, elem->name);
+       prepvarinfo (db, elem->fullname?elem->fullname:prefix, &elem->varinfo, parvi);
+       if (elem->varinfo.dead)
+               return;
+       if (elem->length != 1 && !elem->stride) {
+               if (elem->type != RNN_ETYPE_REG) {
+                       fprintf (stderr, "%s has non-1 length, but no stride!\n", elem->fullname);
+                       db->estatus = 1;
+               } else {
+                       elem->stride = elem->width/width;
+               }
+       }
+       preptypeinfo(db, &elem->typeinfo, elem->name?elem->fullname:prefix, &elem->varinfo, elem->file);
+
+       int i;
+       for (i = 0; i < elem->subelemsnum; i++)
+               prepdelem(db,  elem->subelems[i], elem->name?elem->fullname:prefix, &elem->varinfo, width);
+       if (elem->varinfo.prefix && elem->name)
+               elem->fullname = catstr(elem->varinfo.prefix, elem->fullname);
+}
+
+static void prepdomain(struct rnndb *db, struct rnndomain *dom) {
+       prepvarinfo (db, dom->name, &dom->varinfo, 0);
+       int i;
+       for (i = 0; i < dom->subelemsnum; i++)
+               prepdelem(db, dom->subelems[i], dom->bare?0:dom->name, &dom->varinfo, dom->width);
+       dom->fullname = catstr(dom->varinfo.prefix, dom->name);
+}
+
+static void prepenum(struct rnndb *db, struct rnnenum *en) {
+       if (en->prepared)
+               return;
+       prepvarinfo (db, en->name, &en->varinfo, 0);
+       int i;
+       if (en->isinline)
+               return;
+       for (i = 0; i < en->valsnum; i++)
+               prepvalue(db, en->vals[i], en->bare?0:en->name, &en->varinfo);
+       en->fullname = catstr(en->varinfo.prefix, en->name);
+       en->prepared = 1;
+}
+
+static void prepbitset(struct rnndb *db, struct rnnbitset *bs) {
+       prepvarinfo (db, bs->name, &bs->varinfo, 0);
+       int i;
+       if (bs->isinline)
+               return;
+       for (i = 0; i < bs->bitfieldsnum; i++)
+               prepbitfield(db, bs->bitfields[i], bs->bare?0:bs->name, &bs->varinfo);
+       bs->fullname = catstr(bs->varinfo.prefix, bs->name);
+}
+
+static void prepspectype(struct rnndb *db, struct rnnspectype *st) {
+       preptypeinfo(db, &st->typeinfo, st->name, 0, st->file); // XXX doesn't exactly make sense...
+}
+
+void rnn_prepdb (struct rnndb *db) {
+       int i;
+       for (i = 0; i < db->enumsnum; i++)
+               prepenum(db, db->enums[i]);
+       for (i = 0; i < db->bitsetsnum; i++)
+               prepbitset(db, db->bitsets[i]);
+       for (i = 0; i < db->domainsnum; i++)
+               prepdomain(db, db->domains[i]);
+       for (i = 0; i < db->spectypesnum; i++)
+               prepspectype(db, db->spectypes[i]);
+}
+
+struct rnnenum *rnn_findenum (struct rnndb *db, const char *name) {
+       int i;
+       for (i = 0; i < db->enumsnum; i++)
+               if (!strcmp(db->enums[i]->name, name))
+                       return db->enums[i];
+       return 0;
+}
+
+struct rnnbitset *rnn_findbitset (struct rnndb *db, const char *name) {
+       int i;
+       for (i = 0; i < db->bitsetsnum; i++)
+               if (!strcmp(db->bitsets[i]->name, name))
+                       return db->bitsets[i];
+       return 0;
+}
+
+struct rnndomain *rnn_finddomain (struct rnndb *db, const char *name) {
+       int i;
+       for (i = 0; i < db->domainsnum; i++)
+               if (!strcmp(db->domains[i]->name, name))
+                       return db->domains[i];
+       return 0;
+}
+
+struct rnnspectype *rnn_findspectype (struct rnndb *db, const char *name) {
+       int i;
+       for (i = 0; i < db->spectypesnum; i++)
+               if (!strcmp(db->spectypes[i]->name, name))
+                       return db->spectypes[i];
+       return 0;
+}
diff --git a/src/freedreno/rnn/rnn.h b/src/freedreno/rnn/rnn.h
new file mode 100644 (file)
index 0000000..f90af09
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2010 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.com>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef RNN_H
+#define RNN_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+struct rnnauthor {
+       char* name;
+       char* email;
+       char* contributions;
+       char* license;
+       char** nicknames;
+       int nicknamesnum;
+       int nicknamesmax;
+};
+
+struct rnncopyright {
+       unsigned firstyear;
+       char* license;
+       struct rnnauthor **authors;
+       int authorsnum;
+       int authorsmax;
+};
+
+struct rnndb {
+       struct rnncopyright copyright;
+       struct rnnenum **enums;
+       int enumsnum;
+       int enumsmax;
+       struct rnnbitset **bitsets;
+       int bitsetsnum;
+       int bitsetsmax;
+       struct rnndomain **domains;
+       int domainsnum;
+       int domainsmax;
+       struct rnngroup **groups;
+       int groupsnum;
+       int groupsmax;
+       struct rnnspectype **spectypes;
+       int spectypesnum;
+       int spectypesmax;
+       char **files;
+       int filesnum;
+       int filesmax;
+       int estatus;
+};
+
+struct rnnvarset {
+       struct rnnenum *venum;
+       int *variants;
+};
+
+struct rnnvarinfo {
+       char *prefixstr;
+       char *varsetstr;
+       char *variantsstr;
+       int dead;
+       struct rnnenum *prefenum;
+       char *prefix;
+       struct rnnvarset **varsets;
+       int varsetsnum;
+       int varsetsmax;
+};
+
+struct rnnenum {
+       char *name;
+       int bare;
+       int isinline;
+       struct rnnvarinfo varinfo;
+       struct rnnvalue **vals;
+       int valsnum;
+       int valsmax;
+       char *fullname;
+       int prepared;
+       char *file;
+};
+
+struct rnnvalue {
+       char *name;
+       int valvalid;
+       uint64_t value;
+       struct rnnvarinfo varinfo;
+       char *fullname;
+       char *file;
+};
+
+struct rnntypeinfo {
+       char *name;
+       enum rnnttype {
+               RNN_TTYPE_INVALID,
+               RNN_TTYPE_INLINE_ENUM,
+               RNN_TTYPE_INLINE_BITSET,
+               RNN_TTYPE_ENUM,
+               RNN_TTYPE_BITSET,
+               RNN_TTYPE_SPECTYPE,
+               RNN_TTYPE_HEX,
+               RNN_TTYPE_INT,
+               RNN_TTYPE_UINT,
+               RNN_TTYPE_FLOAT,
+               RNN_TTYPE_BOOLEAN,
+               RNN_TTYPE_FIXED,
+               RNN_TTYPE_UFIXED,
+               RNN_TTYPE_A3XX_REGID,
+       } type;
+       struct rnnenum *eenum;
+       struct rnnbitset *ebitset;
+       struct rnnspectype *spectype;
+       struct rnnbitfield **bitfields;
+       int bitfieldsnum;
+       int bitfieldsmax;
+       struct rnnvalue **vals;
+       int valsnum;
+       int valsmax;
+       int shr, low, high;
+       uint64_t min, max, align, radix;
+       int addvariant;
+       int minvalid, maxvalid, alignvalid, radixvalid;
+};
+
+static inline uint64_t typeinfo_mask(struct rnntypeinfo *ti)
+{
+       if (ti->high == 63)
+               return -(1ULL << ti->low);
+       else
+               return (1ULL << (ti->high + 1)) - (1ULL << ti->low);
+}
+
+struct rnnbitset {
+       char *name;
+       int bare;
+       int isinline;
+       struct rnnvarinfo varinfo;
+       struct rnnbitfield **bitfields;
+       int bitfieldsnum;
+       int bitfieldsmax;
+       char *fullname;
+       char *file;
+};
+
+struct rnnbitfield {
+       char *name;
+       struct rnnvarinfo varinfo;
+       struct rnntypeinfo typeinfo;
+       char *fullname;
+       char *file;
+};
+
+struct rnndomain {
+       char *name;
+       int bare;
+       int width;
+       uint64_t size;
+       int sizevalid;
+       struct rnnvarinfo varinfo;
+       struct rnndelem **subelems;
+       int subelemsnum;
+       int subelemsmax;
+       char *fullname;
+       char *file;
+};
+
+struct rnngroup {
+       char *name;
+       struct rnndelem **subelems;
+       int subelemsnum;
+       int subelemsmax;
+};
+
+struct rnndelem {
+       enum rnnetype {
+               RNN_ETYPE_REG,
+               RNN_ETYPE_ARRAY,
+               RNN_ETYPE_STRIPE,
+               RNN_ETYPE_USE_GROUP,
+       } type;
+       char *name;
+       int width;
+       enum rnnaccess {
+               RNN_ACCESS_R,
+               RNN_ACCESS_W,
+               RNN_ACCESS_RW,
+       } access;
+       uint64_t offset;
+       uint64_t *offsets;       /* for "array" with irregular offsets */
+       int offsetsnum;
+       int offsetsmax;
+       char *doffset;
+       char **doffsets;
+       int doffsetsnum;
+       int doffsetsmax;
+       uint64_t length;
+       uint64_t stride;
+       struct rnndelem **subelems;
+       int subelemsnum;
+       int subelemsmax;
+       struct rnnvarinfo varinfo;
+       struct rnntypeinfo typeinfo;
+       struct rnnenum *index;   /* for arrays, for symbolic idx values */
+       char *fullname;
+       char *file;
+};
+
+struct rnnspectype {
+       char *name;
+       struct rnntypeinfo typeinfo;
+       char *file;
+};
+
+void rnn_init(void);
+struct rnndb *rnn_newdb(void);
+void rnn_parsefile (struct rnndb *db, char *file);
+void rnn_prepdb (struct rnndb *db);
+struct rnnenum *rnn_findenum (struct rnndb *db, const char *name);
+struct rnnbitset *rnn_findbitset (struct rnndb *db, const char *name);
+struct rnndomain *rnn_finddomain (struct rnndb *db, const char *name);
+struct rnnspectype *rnn_findspectype (struct rnndb *db, const char *name);
+
+#endif
diff --git a/src/freedreno/rnn/rnn_path.h b/src/freedreno/rnn/rnn_path.h
new file mode 100644 (file)
index 0000000..3582425
--- /dev/null
@@ -0,0 +1 @@
+#define RNN_DEF_PATH SOURCE_DIR "/src/freedreno/registers:" INSTALL_DIR "share/mesa/freedreno/registers"
diff --git a/src/freedreno/rnn/rnndec.c b/src/freedreno/rnn/rnndec.c
new file mode 100644 (file)
index 0000000..db449a2
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2010 Francisco Jerez <currojerez@riseup.net>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define _GNU_SOURCE // for asprintf
+#include "rnndec.h"
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "util.h"
+
+struct rnndeccontext *rnndec_newcontext(struct rnndb *db) {
+       struct rnndeccontext *res = calloc (sizeof *res, 1);
+       res->db = db;
+       res->colors = &envy_null_colors;
+       return res;
+}
+
+int rnndec_varadd(struct rnndeccontext *ctx, char *varset, char *variant) {
+       struct rnnenum *en = rnn_findenum(ctx->db, varset);
+       if (!en) {
+               fprintf (stderr, "Enum %s doesn't exist in database!\n", varset);
+               return 0;
+       }
+       int i, j;
+       for (i = 0; i < en->valsnum; i++)
+               if (!strcasecmp(en->vals[i]->name, variant)) {
+                       struct rnndecvariant *ci = calloc (sizeof *ci, 1);
+                       ci->en = en;
+                       ci->variant = i;
+                       ADDARRAY(ctx->vars, ci);
+                       return 1;
+               }
+
+       if (i == en->valsnum) {
+               fprintf (stderr, "Variant %s doesn't exist in enum %s!\n", variant, varset);
+               return 0;
+       }
+
+       for (j = 0; j < ctx->varsnum; j++) {
+               if (ctx->vars[j]->en == en) {
+                       ctx->vars[j]->variant = i;
+                       break;
+               }
+       }
+
+       if (i == ctx->varsnum) {
+               struct rnndecvariant *ci = calloc (sizeof *ci, 1);
+               ci->en = en;
+               ci->variant = i;
+               ADDARRAY(ctx->vars, ci);
+       }
+
+       return 1;
+}
+
+int rnndec_varmatch(struct rnndeccontext *ctx, struct rnnvarinfo *vi) {
+       if (vi->dead)
+               return 0;
+       int i;
+       for (i = 0; i < vi->varsetsnum; i++) {
+               int j;
+               for (j = 0; j < ctx->varsnum; j++)
+                       if (vi->varsets[i]->venum == ctx->vars[j]->en)
+                               break;
+               if (j == ctx->varsnum) {
+                       fprintf (stderr, "I don't know which %s variant to use!\n", vi->varsets[i]->venum->name);
+               } else {
+                       if (!vi->varsets[i]->variants[ctx->vars[j]->variant])
+                               return 0;
+               }
+       }
+       return 1;
+}
+
+/* see https://en.wikipedia.org/wiki/Half-precision_floating-point_format */
+static uint32_t float16i(uint16_t val)
+{
+       uint32_t sign = ((uint32_t)(val & 0x8000)) << 16;
+       uint32_t frac = val & 0x3ff;
+       int32_t  expn = (val >> 10) & 0x1f;
+
+       if (expn == 0) {
+               if (frac) {
+                       /* denormalized number: */
+                       int shift = __builtin_clz(frac) - 21;
+                       frac <<= shift;
+                       expn = -shift;
+               } else {
+                       /* +/- zero: */
+                       return sign;
+               }
+       } else if (expn == 0x1f) {
+               /* Inf/NaN: */
+               return sign | 0x7f800000 | (frac << 13);
+       }
+
+       return sign | ((expn + 127 - 15) << 23) | (frac << 13);
+}
+static float float16(uint16_t val)
+{
+       union { uint32_t i; float f; } u;
+       u.i = float16i(val);
+       return u.f;
+}
+
+static const char *rnndec_decode_enum_val(struct rnndeccontext *ctx,
+               struct rnnvalue **vals, int valsnum, uint64_t value)
+{
+       int i;
+       for (i = 0; i < valsnum; i++)
+               if (rnndec_varmatch(ctx, &vals[i]->varinfo) &&
+                               vals[i]->valvalid && vals[i]->value == value)
+                       return vals[i]->name;
+       return NULL;
+}
+
+char *rnndec_decode_enum(struct rnndeccontext *ctx, const char *enumname, uint64_t enumval)
+{
+       struct rnnenum *en = rnn_findenum (ctx->db, enumname);
+       if (en) {
+               int i;
+               for (i = 0; i < en->valsnum; i++)
+                       if (en->vals[i]->valvalid && en->vals[i]->value == enumval)
+                               return en->vals[i]->name;
+       }
+       return NULL;
+}
+
+/* The name UNK%u is used as a placeholder for bitfields that exist but
+ * have an unknown function.
+ */
+static int is_unknown(const char *name)
+{
+       unsigned u;
+       return sscanf(name, "UNK%u", &u) == 1;
+}
+
+char *rnndec_decodeval(struct rnndeccontext *ctx, struct rnntypeinfo *ti, uint64_t value) {
+       int width = ti->high - ti->low + 1;
+       char *res = 0;
+       int i;
+       struct rnnvalue **vals;
+       int valsnum;
+       struct rnnbitfield **bitfields;
+       int bitfieldsnum;
+       char *tmp;
+       uint64_t mask, value_orig;
+       if (!ti)
+               goto failhex;
+       value_orig = value;
+       value = (value & typeinfo_mask(ti)) >> ti->low;
+       value <<= ti->shr;
+
+       switch (ti->type) {
+               case RNN_TTYPE_ENUM:
+                       vals = ti->eenum->vals;
+                       valsnum = ti->eenum->valsnum;
+                       goto doenum;
+               case RNN_TTYPE_INLINE_ENUM:
+                       vals = ti->vals;
+                       valsnum = ti->valsnum;
+                       goto doenum;
+               doenum:
+                       tmp = rnndec_decode_enum_val(ctx, vals, valsnum, value);
+                       if (tmp) {
+                               asprintf (&res, "%s%s%s", ctx->colors->eval, tmp, ctx->colors->reset);
+                               if (ti->addvariant) {
+                                       rnndec_varadd(ctx, ti->eenum->name, tmp);
+                               }
+                               break;
+                       }
+                       goto failhex;
+               case RNN_TTYPE_BITSET:
+                       bitfields = ti->ebitset->bitfields;
+                       bitfieldsnum = ti->ebitset->bitfieldsnum;
+                       goto dobitset;
+               case RNN_TTYPE_INLINE_BITSET:
+                       bitfields = ti->bitfields;
+                       bitfieldsnum = ti->bitfieldsnum;
+                       goto dobitset;
+               dobitset:
+                       mask = 0;
+                       for (i = 0; i < bitfieldsnum; i++) {
+                               if (!rnndec_varmatch(ctx, &bitfields[i]->varinfo))
+                                       continue;
+                               uint64_t type_mask = typeinfo_mask(&bitfields[i]->typeinfo);
+                               if (((value & type_mask) == 0) && is_unknown(bitfields[i]->name))
+                                       continue;
+                               mask |= type_mask;
+                               if (bitfields[i]->typeinfo.type == RNN_TTYPE_BOOLEAN) {
+                                       const char *color = is_unknown(bitfields[i]->name) ?
+                                                       ctx->colors->err : ctx->colors->mod;
+                                       if (value & type_mask) {
+                                               if (!res)
+                                                       asprintf (&res, "%s%s%s", color, bitfields[i]->name, ctx->colors->reset);
+                                               else {
+                                                       asprintf (&tmp, "%s | %s%s%s", res, color, bitfields[i]->name, ctx->colors->reset);
+                                                       free(res);
+                                                       res = tmp;
+                                               }
+                                       }
+                                       continue;
+                               }
+                               char *subval;
+                               if (is_unknown(bitfields[i]->name) && (bitfields[i]->typeinfo.type != RNN_TTYPE_A3XX_REGID)) {
+                                       uint64_t field_val = value & type_mask;
+                                       field_val = (field_val & typeinfo_mask(&bitfields[i]->typeinfo)) >> bitfields[i]->typeinfo.low;
+                                       field_val <<= bitfields[i]->typeinfo.shr;
+                                       asprintf (&subval, "%s%#"PRIx64"%s", ctx->colors->err, field_val, ctx->colors->reset);
+                               } else {
+                                       subval = rnndec_decodeval(ctx, &bitfields[i]->typeinfo, value & type_mask);
+                               }
+                               if (!res)
+                                       asprintf (&res, "%s%s%s = %s", ctx->colors->rname, bitfields[i]->name, ctx->colors->reset, subval);
+                               else {
+                                       asprintf (&tmp, "%s | %s%s%s = %s", res, ctx->colors->rname, bitfields[i]->name, ctx->colors->reset, subval);
+                                       free(res);
+                                       res = tmp;
+                               }
+                               free(subval);
+                       }
+                       if (value & ~mask) {
+                               if (!res)
+                                       asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->err, value & ~mask, ctx->colors->reset);
+                               else {
+                                       asprintf (&tmp, "%s | %s%#"PRIx64"%s", res, ctx->colors->err, value & ~mask, ctx->colors->reset);
+                                       free(res);
+                                       res = tmp;
+                               }
+                       }
+                       if (!res)
+                               asprintf (&res, "%s0%s", ctx->colors->num, ctx->colors->reset);
+                       asprintf (&tmp, "{ %s }", res);
+                       free(res);
+                       return tmp;
+               case RNN_TTYPE_SPECTYPE:
+                       return rnndec_decodeval(ctx, &ti->spectype->typeinfo, value);
+               case RNN_TTYPE_HEX:
+                       asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->num, value, ctx->colors->reset);
+                       break;
+               case RNN_TTYPE_FIXED:
+                       if (value & UINT64_C(1) << (width-1)) {
+                               asprintf (&res, "%s-%lf%s", ctx->colors->num,
+                                               ((double)((UINT64_C(1) << width) - value)) / ((double)(1 << ti->radix)),
+                                               ctx->colors->reset);
+                               break;
+                       }
+                       /* fallthrough */
+               case RNN_TTYPE_UFIXED:
+                       asprintf (&res, "%s%lf%s", ctx->colors->num,
+                                       ((double)value) / ((double)(1LL << ti->radix)),
+                                       ctx->colors->reset);
+                       break;
+               case RNN_TTYPE_A3XX_REGID:
+                       asprintf (&res, "%sr%"PRIu64".%c%s", ctx->colors->num, (value >> 2), "xyzw"[value & 0x3], ctx->colors->reset);
+                       break;
+               case RNN_TTYPE_UINT:
+                       asprintf (&res, "%s%"PRIu64"%s", ctx->colors->num, value, ctx->colors->reset);
+                       break;
+               case RNN_TTYPE_INT:
+                       if (value & UINT64_C(1) << (width-1))
+                               asprintf (&res, "%s-%"PRIi64"%s", ctx->colors->num, (UINT64_C(1) << width) - value, ctx->colors->reset);
+                       else
+                               asprintf (&res, "%s%"PRIi64"%s", ctx->colors->num, value, ctx->colors->reset);
+                       break;
+               case RNN_TTYPE_BOOLEAN:
+                       if (value == 0) {
+                               asprintf (&res, "%sFALSE%s", ctx->colors->eval, ctx->colors->reset);
+                       } else if (value == 1) {
+                               asprintf (&res, "%sTRUE%s", ctx->colors->eval, ctx->colors->reset);
+                       }
+                       break;
+               case RNN_TTYPE_FLOAT: {
+                       union { uint64_t i; float f; double d; } val;
+                       val.i = value;
+                       if (width == 64)
+                               asprintf(&res, "%s%f%s", ctx->colors->num,
+                                       val.d, ctx->colors->reset);
+                       else if (width == 32)
+                               asprintf(&res, "%s%f%s", ctx->colors->num,
+                                       val.f, ctx->colors->reset);
+                       else if (width == 16)
+                               asprintf(&res, "%s%f%s", ctx->colors->num,
+                                       float16(value), ctx->colors->reset);
+                       else
+                               goto failhex;
+
+                       break;
+               }
+               failhex:
+               default:
+                       asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->num, value, ctx->colors->reset);
+                       break;
+       }
+       if (value_orig & ~typeinfo_mask(ti)) {
+               asprintf (&tmp, "%s | %s%#"PRIx64"%s", res, ctx->colors->err, value_orig & ~typeinfo_mask(ti), ctx->colors->reset);
+               free(res);
+               res = tmp;
+       }
+       return res;
+}
+
+static char *appendidx (struct rnndeccontext *ctx, char *name, uint64_t idx, struct rnnenum *index) {
+       char *res, *index_name = NULL;
+
+       if (index)
+               index_name = rnndec_decode_enum_val(ctx, index->vals, index->valsnum, idx);
+
+       if (index_name)
+               asprintf (&res, "%s[%s%s%s]", name, ctx->colors->eval, index_name, ctx->colors->reset);
+       else
+               asprintf (&res, "%s[%s%#"PRIx64"%s]", name, ctx->colors->num, idx, ctx->colors->reset);
+
+       free (name);
+       return res;
+}
+
+/* This could probably be made to work for stripes too.. */
+static int get_array_idx_offset(struct rnndelem *elem, uint64_t addr, uint64_t *idx, uint64_t *offset)
+{
+       if (elem->offsets) {
+               int i;
+               for (i = 0; i < elem->offsetsnum; i++) {
+                       uint64_t o = elem->offsets[i];
+                       if ((o <= addr) && (addr < (o + elem->stride))) {
+                               *idx = i;
+                               *offset = addr - o;
+                               return 0;
+                       }
+               }
+               return -1;
+       } else {
+               if (addr < elem->offset)
+                       return -1;
+
+               *idx = (addr - elem->offset) / elem->stride;
+               *offset = (addr - elem->offset) % elem->stride;
+
+               if (elem->length && (*idx >= elem->length))
+                       return -1;
+
+               return 0;
+       }
+}
+
+static struct rnndecaddrinfo *trymatch (struct rnndeccontext *ctx, struct rnndelem **elems, int elemsnum, uint64_t addr, int write, int dwidth, uint64_t *indices, int indicesnum) {
+       struct rnndecaddrinfo *res;
+       int i, j;
+       for (i = 0; i < elemsnum; i++) {
+               if (!rnndec_varmatch(ctx, &elems[i]->varinfo))
+                       continue;
+               uint64_t offset, idx;
+               char *tmp, *name;
+               switch (elems[i]->type) {
+                       case RNN_ETYPE_REG:
+                               if (addr < elems[i]->offset)
+                                       break;
+                               if (elems[i]->stride) {
+                                       idx = (addr-elems[i]->offset)/elems[i]->stride;
+                                       offset = (addr-elems[i]->offset)%elems[i]->stride;
+                               } else {
+                                       idx = 0;
+                                       offset = addr-elems[i]->offset;
+                               }
+                               if (offset >= elems[i]->width/dwidth)
+                                       break;
+                               if (elems[i]->length && idx >= elems[i]->length)
+                                       break;
+                               res = calloc (sizeof *res, 1);
+                               res->typeinfo = &elems[i]->typeinfo;
+                               res->width = elems[i]->width;
+                               asprintf (&res->name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
+                               for (j = 0; j < indicesnum; j++)
+                                       res->name = appendidx(ctx, res->name, indices[j], NULL);
+                               if (elems[i]->length != 1)
+                                       res->name = appendidx(ctx, res->name, idx, elems[i]->index);
+                               if (offset) {
+                                       asprintf (&tmp, "%s+%s%#"PRIx64"%s", res->name, ctx->colors->err, offset, ctx->colors->reset);
+                                       free(res->name);
+                                       res->name = tmp;
+                               }
+                               return res;
+                       case RNN_ETYPE_STRIPE:
+                               for (idx = 0; idx < elems[i]->length || !elems[i]->length; idx++) {
+                                       if (addr < elems[i]->offset + elems[i]->stride * idx)
+                                               break;
+                                       offset = addr - (elems[i]->offset + elems[i]->stride * idx);
+                                       int extraidx = (elems[i]->length != 1);
+                                       int nindnum = (elems[i]->name ? 0 : indicesnum + extraidx);
+                                       uint64_t nind[nindnum];
+                                       if (!elems[i]->name) {
+                                               for (j = 0; j < indicesnum; j++)
+                                                       nind[j] = indices[j];
+                                               if (extraidx)
+                                                       nind[indicesnum] = idx;
+                                       }
+                                       res = trymatch (ctx, elems[i]->subelems, elems[i]->subelemsnum, offset, write, dwidth, nind, nindnum);
+                                       if (!res)
+                                               continue;
+                                       if (!elems[i]->name)
+                                               return res;
+                                       asprintf (&name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
+                                       for (j = 0; j < indicesnum; j++)
+                                               name = appendidx(ctx, name, indices[j], NULL);
+                                       if (elems[i]->length != 1)
+                                               name = appendidx(ctx, name, idx, elems[i]->index);
+                                       asprintf (&tmp, "%s.%s", name, res->name);
+                                       free(name);
+                                       free(res->name);
+                                       res->name = tmp;
+                                       return res;
+                               }
+                               break;
+                       case RNN_ETYPE_ARRAY:
+                               if (get_array_idx_offset(elems[i], addr, &idx, &offset))
+                                       break;
+                               asprintf (&name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
+                               for (j = 0; j < indicesnum; j++)
+                                       name = appendidx(ctx, name, indices[j], NULL);
+                               if (elems[i]->length != 1)
+                                       name = appendidx(ctx, name, idx, elems[i]->index);
+                               if ((res = trymatch (ctx, elems[i]->subelems, elems[i]->subelemsnum, offset, write, dwidth, 0, 0))) {
+                                       asprintf (&tmp, "%s.%s", name, res->name);
+                                       free(name);
+                                       free(res->name);
+                                       res->name = tmp;
+                                       return res;
+                               }
+                               res = calloc (sizeof *res, 1);
+                               asprintf (&tmp, "%s+%s%#"PRIx64"%s", name, ctx->colors->err, offset, ctx->colors->reset);
+                               free(name);
+                               res->name = tmp;
+                               return res;
+                       default:
+                               break;
+               }
+       }
+       return 0;
+}
+
+int rnndec_checkaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write) {
+       struct rnndecaddrinfo *res = trymatch(ctx, domain->subelems, domain->subelemsnum, addr, write, domain->width, 0, 0);
+       if (res) {
+               free(res->name);
+               free(res);
+       }
+       return res != NULL;
+}
+
+struct rnndecaddrinfo *rnndec_decodeaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write) {
+       struct rnndecaddrinfo *res = trymatch(ctx, domain->subelems, domain->subelemsnum, addr, write, domain->width, 0, 0);
+       if (res)
+               return res;
+       res = calloc (sizeof *res, 1);
+       asprintf (&res->name, "%s%#"PRIx64"%s", ctx->colors->err, addr, ctx->colors->reset);
+       return res;
+}
+
+static uint64_t tryreg(struct rnndeccontext *ctx, struct rnndelem **elems, int elemsnum,
+               int dwidth, const char *name)
+{
+       int i;
+       const char *suffix = strchr(name, '[');
+       unsigned n = suffix ? (suffix - name) : strlen(name);
+
+       const char *child = NULL;
+       unsigned idx = 0;
+
+       if (suffix) {
+               const char *tmp = strchr(suffix, ']');
+               idx = strtol(suffix+1, NULL, 0);
+               child = tmp+2;
+       }
+
+       for (i = 0; i < elemsnum; i++) {
+               struct rnndelem *elem = elems[i];
+               if (!rnndec_varmatch(ctx, &elem->varinfo))
+                       continue;
+               int match = (strlen(elem->name) == n) && !strncmp(elem->name, name, n);
+               switch (elem->type) {
+                       case RNN_ETYPE_REG:
+                               if (match) {
+                                       assert(!suffix);
+                                       return elem->offset;
+                               }
+                               break;
+                       case RNN_ETYPE_STRIPE:
+                               assert(0); // TODO
+                               break;
+                       case RNN_ETYPE_ARRAY:
+                               if (match) {
+                                       assert(suffix);
+                                       return elem->offset + (idx * elem->stride) +
+                                               tryreg(ctx, elem->subelems, elem->subelemsnum, dwidth, child);
+                               }
+                               break;
+                       default:
+                               break;
+               }
+       }
+       return 0;
+}
+
+uint64_t rnndec_decodereg(struct rnndeccontext *ctx, struct rnndomain *domain, const char *name)
+{
+       return tryreg(ctx, domain->subelems, domain->subelemsnum, domain->width, name);
+}
diff --git a/src/freedreno/rnn/rnndec.h b/src/freedreno/rnn/rnndec.h
new file mode 100644 (file)
index 0000000..c782d21
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Marcin Kościelnicki <koriakin@0x04.net>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef RNNDEC_H
+#define RNNDEC_H
+
+#include "rnn.h"
+#include "colors.h"
+
+struct rnndecvariant {
+       struct rnnenum *en;
+       int variant;
+};
+
+struct rnndeccontext {
+       struct rnndb *db;
+       struct rnndecvariant **vars;
+       int varsnum;
+       int varsmax;
+       const struct envy_colors *colors;
+};
+
+struct rnndecaddrinfo {
+       struct rnntypeinfo *typeinfo;
+       int width;
+       char *name;
+};
+
+struct rnndeccontext *rnndec_newcontext(struct rnndb *db);
+int rnndec_varadd(struct rnndeccontext *ctx, char *varset, char *variant);
+int rnndec_varmatch(struct rnndeccontext *ctx, struct rnnvarinfo *vi);
+char *rnndec_decode_enum(struct rnndeccontext *ctx, const char *enumname, uint64_t enumval);
+char *rnndec_decodeval(struct rnndeccontext *ctx, struct rnntypeinfo *ti, uint64_t value);
+int rnndec_checkaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write);
+struct rnndecaddrinfo *rnndec_decodeaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write);
+uint64_t rnndec_decodereg(struct rnndeccontext *ctx, struct rnndomain *domain, const char *name);
+
+#endif
diff --git a/src/freedreno/rnn/util.h b/src/freedreno/rnn/util.h
new file mode 100644 (file)
index 0000000..98a32a3
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2010 Francisco Jerez <currojerez@riseup.net>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#define ADDARRAY(a, e) \
+       do { \
+       if ((a ## num) >= (a ## max)) { \
+               if (!(a ## max)) \
+                       (a ## max) = 16; \
+               else \
+                       (a ## max) *= 2; \
+               (a) = realloc((a), (a ## max)*sizeof(*(a))); \
+       } \
+       (a)[(a ## num)++] = (e); \
+       } while(0)
+
+#define FINDARRAY(a, tmp, pred)                                \
+       ({                                                      \
+               int __i;                                        \
+                                                               \
+               for (__i = 0; __i < (a ## num); __i++) {        \
+                       tmp = (a)[__i];                         \
+                       if (pred)                               \
+                               break;                          \
+               }                                               \
+                                                               \
+               tmp = ((pred) ? tmp : NULL);                    \
+       })
+
+/* ceil(log2(x)) */
+static inline int clog2(uint64_t x) {
+       if (!x)
+               return x;
+       int r = 0;
+       while (x - 1 > (1ull << r) - 1)
+               r++;
+       return r;
+}
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
+
+#define min(a,b)                               \
+       ({                                      \
+               typeof (a) _a = (a);            \
+               typeof (b) _b = (b);            \
+               _a < _b ? _a : _b;              \
+       })
+
+#define max(a,b)                               \
+       ({                                      \
+               typeof (a) _a = (a);            \
+               typeof (b) _b = (b);            \
+               _a > _b ? _a : _b;              \
+       })
+
+#define CEILDIV(a, b) (((a) + (b) - 1)/(b))
+
+#define extr(a, b, c) ((uint64_t)(a) << (64 - (b) - (c)) >> (64 - (c)))
+#define extrs(a, b, c) ((int64_t)(a) << (64 - (b) - (c)) >> (64 - (c))) 
+#define sext(a, b) extrs(a, 0, b+1)
+#define bflmask(a) ((2ull << ((a)-1)) - 1)
+#define insrt(a, b, c, d) ((a) = ((a) & ~(bflmask(c) << (b))) | ((d) & bflmask(c)) << (b))
+
+struct envy_loc {
+       int lstart;
+       int cstart;
+       int lend;
+       int cend;
+       const char *file;
+};
+
+#define LOC_FORMAT(loc, str) "%s:%d.%d-%d.%d: " str, (loc).file, (loc).lstart, (loc).cstart, (loc).lend, (loc).cend
+
+uint32_t elf_hash(const char *str);
+
+FILE *find_in_path(const char *name, const char *path, char **pfullname);
+
+struct astr {
+       char *str;
+       size_t len;
+};
+
+void print_escaped_astr(FILE *out, struct astr *astr);
+
+char *aprintf(const char *format, ...);
+
+#endif