34a49a01ba3c085101096a38c2f60462d481b605
[mesa.git] / src / freedreno / rnn / headergen2.c
1 /*
2 * Copyright (C) 2013 Rob Clark <robdclark@gmail.com>
3 * Copyright (C) 2010-2011 Marcin Koƛcielnicki <koriakin@0x04.net>
4 * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.com>
5 * Copyright (C) 2010 Marcin Slusarz <marcin.slusarz@gmail.com>
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28 /* modified version of headergen which uses enums and inline fxns for
29 * type safety.. based on original headergen
30 */
31 #define _GNU_SOURCE
32
33 #include "rnn.h"
34 #include "util.h"
35 #include <stdbool.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <inttypes.h>
39 #include <time.h>
40 #include <ctype.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <sys/stat.h>
44 #include <sys/wait.h>
45 #include <assert.h>
46
47 struct rnndelem **elems = NULL;
48 int elemsnum = 0;
49 int elemsmax = 0;
50
51 char **offsetfns = NULL;
52 int offsetfnsnum = 0;
53 int offsetfnsmax = 0;
54
55 int startcol = 64;
56
57 struct fout {
58 char *name;
59 FILE *file;
60 char *guard;
61 };
62
63 struct fout *fouts = 0;
64 int foutsnum = 0;
65 int foutsmax = 0;
66
67 static bool no_asserts = false;
68
69 static void seekcol (FILE *f, int src, int dst) {
70 if (dst <= src)
71 fprintf (f, "\t");
72 else {
73 int n = dst/8 - src/8;
74 if (n) {
75 while (n--)
76 fprintf (f, "\t");
77 n = dst&7;
78 } else
79 n = dst-src;
80 while (n--)
81 fprintf (f, " ");
82 }
83 }
84
85 static FILE *findfout (char *file) {
86 int i;
87 for (i = 0; i < foutsnum; i++)
88 if (!strcmp(fouts[i].name, file))
89 break;
90 if (i == foutsnum) {
91 fprintf (stderr, "AIII, didn't open file %s.\n", file);
92 exit(1);
93 }
94 return fouts[i].file;
95 }
96
97 static void printdef (char *name, char *suf, int type, uint64_t val, char *file) {
98 FILE *dst = findfout(file);
99 int len;
100 if (suf)
101 fprintf (dst, "#define %s__%s%n", name, suf, &len);
102 else
103 fprintf (dst, "#define %s%n", name, &len);
104 if (type == 0 && val > 0xffffffffull)
105 seekcol (dst, len, startcol-8);
106 else
107 seekcol (dst, len, startcol);
108 switch (type) {
109 case 0:
110 if (val > 0xffffffffull)
111 fprintf (dst, "0x%016"PRIx64"ULL\n", val);
112 else
113 fprintf (dst, "0x%08"PRIx64"\n", val);
114 break;
115 case 1:
116 fprintf (dst, "%"PRIu64"\n", val);
117 break;
118 }
119 }
120
121 static void printvalue (struct rnnvalue *val, int shift) {
122 if (val->varinfo.dead)
123 return;
124 if (val->valvalid)
125 printdef (val->fullname, 0, 0, val->value << shift, val->file);
126 }
127
128 static void printbitfield (struct rnnbitfield *bf, int shift);
129
130 static void printtypeinfo (struct rnntypeinfo *ti, struct rnnbitfield *bf,
131 char *prefix, char *file) {
132 FILE *dst = findfout(file);
133 enum rnnttype intype = ti->type;
134 char *typename = NULL;
135 uint32_t mask = typeinfo_mask(ti);
136 uint32_t width = 1 + ti->high - ti->low;
137
138 /* for fixed point, input type (arg to fxn) is float: */
139 if ((ti->type == RNN_TTYPE_FIXED) || (ti->type == RNN_TTYPE_UFIXED))
140 intype = RNN_TTYPE_FLOAT;
141
142 /* for toplevel register (ie. not bitfield), only generate accessor
143 * fxn for special cases (float, shr, min/max, etc):
144 */
145 if (bf || ti->shr || ti->minvalid || ti->maxvalid || ti->alignvalid ||
146 ti->radixvalid || (intype == RNN_TTYPE_FLOAT)) {
147 switch (intype) {
148 case RNN_TTYPE_HEX:
149 case RNN_TTYPE_UINT:
150 case RNN_TTYPE_A3XX_REGID:
151 typename = "uint32_t";
152 break;
153 case RNN_TTYPE_INT:
154 typename = "int32_t";
155 break;
156 case RNN_TTYPE_FLOAT:
157 typename = "float";
158 break;
159 case RNN_TTYPE_ENUM:
160 asprintf(&typename, "enum %s", ti->name);
161 break;
162 }
163 }
164
165 /* for boolean, just generate a #define flag.. rather than inline fxn */
166 if (bf && (intype == RNN_TTYPE_BOOLEAN)) {
167 printdef(bf->fullname, 0, 0, mask, file);
168 return;
169 }
170
171 if (typename) {
172 printdef(prefix, "MASK", 0, mask, file);
173 printdef(prefix, "SHIFT", 1, ti->low, file);
174
175 fprintf(dst, "static inline uint32_t %s(%s val)\n", prefix, typename);
176 fprintf(dst, "{\n");
177
178 if ((ti->minvalid || ti->maxvalid || ti->alignvalid) && !no_asserts) {
179 fprintf(dst, "\tassert(1");
180 if (ti->minvalid)
181 fprintf(dst, " && (val >= %lu)", ti->min);
182 if (ti->maxvalid)
183 fprintf(dst, " && (val <= %lu)", ti->max);
184 if (ti->alignvalid)
185 fprintf(dst, " && !(val %% %lu)", ti->align);
186 fprintf(dst, ");\n");
187 }
188
189 if (ti->shr && !no_asserts) {
190 fprintf(dst, "\tassert(!(val & 0x%x));\n", (1 << ti->shr) - 1);
191 }
192
193 fprintf(dst, "\treturn ((");
194
195 if (ti->type == RNN_TTYPE_FIXED) {
196 fprintf(dst, "((int32_t)(val * %d.0))", (1 << ti->radix));
197 } else if (ti->type == RNN_TTYPE_UFIXED) {
198 fprintf(dst, "((uint32_t)(val * %d.0))", (1 << ti->radix));
199 } else if (ti->type == RNN_TTYPE_FLOAT) {
200 if (width == 32)
201 fprintf(dst, "fui(val)");
202 else if (width == 16)
203 fprintf(dst, "util_float_to_half(val)");
204 else
205 assert(!"invalid float size");
206 } else {
207 fprintf(dst, "val");
208 }
209
210 if (ti->shr)
211 fprintf(dst, " >> %d", ti->shr);
212
213 fprintf(dst, ") << %s__SHIFT) & %s__MASK;\n", prefix, prefix);
214 fprintf(dst, "}\n");
215
216 if (intype == RNN_TTYPE_ENUM)
217 free(typename);
218 }
219
220 int i;
221 for (i = 0; i < ti->valsnum; i++)
222 printvalue(ti->vals[i], ti->low);
223 for (i = 0; i < ti->bitfieldsnum; i++)
224 printbitfield(ti->bitfields[i], ti->low);
225 }
226
227 static void printbitfield (struct rnnbitfield *bf, int shift) {
228 if (bf->varinfo.dead)
229 return;
230 printtypeinfo (&bf->typeinfo, bf, bf->fullname, bf->file);
231 }
232
233 static void printdelem (struct rnndelem *elem, uint64_t offset) {
234 int use_offset_fxn;
235 char *offsetfn = NULL;
236
237 if (elem->varinfo.dead)
238 return;
239
240 use_offset_fxn = elem->offsets || elem->doffset || elem->doffsets;
241 assert((!!elem->offsets + !!elem->doffset + !!elem->doffsets) <= 1);
242
243 if (use_offset_fxn)
244 asprintf(&offsetfn, "__offset_%s", elem->name);
245
246 if (elem->length != 1) {
247 ADDARRAY(elems, elem);
248 ADDARRAY(offsetfns, offsetfn);
249 }
250
251 if (elem->name) {
252 char *regname;
253 asprintf(&regname, "REG_%s", elem->fullname);
254 if (elemsnum) {
255 int len;
256 FILE *dst = findfout(elem->file);
257 int i;
258
259 if (use_offset_fxn) {
260 fprintf(dst, "static inline uint32_t %s(", offsetfn);
261 if (elem->index)
262 fprintf(dst, "enum %s", elem->index->name);
263 else
264 fprintf(dst, "uint32_t");
265 fprintf(dst, " idx)\n");
266 fprintf(dst, "{\n");
267 if (elem->doffset) {
268 fprintf(dst, "\treturn (%s) + (%#" PRIx64 "*idx);\n", elem->doffset, elem->stride);
269 } else {
270 int valuesnum = elem->doffsets ? elem->doffsetsnum : elem->offsetsnum;
271
272 fprintf(dst, "\tswitch (idx) {\n");
273 for (i = 0; i < valuesnum; i++) {
274 struct rnnvalue *val = NULL;
275 fprintf(dst, "\t\tcase ");
276 if (elem->index) {
277 int j;
278 for (j = 0; j < elem->index->valsnum; j++) {
279 if (elem->index->vals[j]->value == i) {
280 val = elem->index->vals[j];
281 break;
282 }
283 }
284 }
285 if (val) {
286 fprintf(dst, "%s", val->name);
287 } else {
288 fprintf(dst, "%d", i);
289 }
290 if (elem->offsets) {
291 fprintf(dst, ": return 0x%08lx;\n", elem->offsets[i]);
292 } else {
293 fprintf(dst, ": return (%s);\n", elem->doffsets[i]);
294 }
295 }
296 fprintf(dst, "\t\tdefault: return INVALID_IDX(idx);\n");
297 fprintf(dst, "\t}\n");
298 }
299 fprintf(dst, "}\n");
300 }
301 fprintf (dst, "static inline uint32_t %s(", regname);
302 for (i = 0; i < elemsnum; i++) {
303 if (i)
304 fprintf(dst, ", ");
305 if (elems[i]->index)
306 fprintf(dst, "enum %s ", elems[i]->index->name);
307 else
308 fprintf(dst, "uint32_t ");
309 fprintf (dst, "i%d%n", i, &len);
310 }
311 fprintf (dst, ") { return ");
312 fprintf (dst, "0x%08"PRIx64"", offset + elem->offset);
313 for (i = 0; i < elemsnum; i++) {
314 if (offsetfns[i])
315 fprintf(dst, " + %s(i%d)", offsetfns[i], i);
316 else
317 fprintf (dst, " + %#" PRIx64 "*i%d", elems[i]->stride, i);
318 }
319 fprintf (dst, "; }\n");
320 } else
321 printdef (regname, 0, 0, offset + elem->offset, elem->file);
322
323 free(regname);
324 /*
325 if (elem->stride)
326 printdef (elem->fullname, "ESIZE", 0, elem->stride, elem->file);
327 if (elem->length != 1)
328 printdef (elem->fullname, "LEN", 0, elem->length, elem->file);
329 */
330 printtypeinfo (&elem->typeinfo, NULL, elem->fullname, elem->file);
331 }
332 fprintf (findfout(elem->file), "\n");
333 int j;
334 for (j = 0; j < elem->subelemsnum; j++) {
335 printdelem(elem->subelems[j], offset + elem->offset);
336 }
337 if (elem->length != 1) {
338 elemsnum--;
339 offsetfnsnum--;
340 }
341 free(offsetfn);
342 }
343
344 static void print_file_info_(FILE *dst, struct stat* sb, struct tm* tm)
345 {
346 char timestr[64];
347 strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
348 fprintf(dst, "(%7Lu bytes, from %s)\n", (unsigned long long)sb->st_size, timestr);
349 }
350
351 static void print_file_info(FILE *dst, const char* file)
352 {
353 struct stat sb;
354 struct tm tm;
355 stat(file, &sb);
356 gmtime_r(&sb.st_mtime, &tm);
357 print_file_info_(dst, &sb, &tm);
358 }
359
360 static void printhead(struct fout f, struct rnndb *db) {
361 int i, j;
362 struct stat sb;
363 struct tm tm;
364 stat(f.name, &sb);
365 gmtime_r(&sb.st_mtime, &tm);
366 fprintf (f.file, "#ifndef %s\n", f.guard);
367 fprintf (f.file, "#define %s\n", f.guard);
368 fprintf (f.file, "\n");
369 fprintf(f.file,
370 "/* Autogenerated file, DO NOT EDIT manually!\n"
371 "\n"
372 "This file was generated by the rules-ng-ng headergen tool in this git repository:\n"
373 "http://github.com/freedreno/envytools/\n"
374 "git clone https://github.com/freedreno/envytools.git\n"
375 "\n"
376 "The rules-ng-ng source files this header was generated from are:\n");
377 unsigned maxlen = 0;
378 for(i = 0; i < db->filesnum; ++i) {
379 unsigned len = strlen(db->files[i]);
380 if(len > maxlen)
381 maxlen = len;
382 }
383 for(i = 0; i < db->filesnum; ++i) {
384 unsigned len = strlen(db->files[i]);
385 fprintf(f.file, "- %s%*s ", db->files[i], maxlen - len, "");
386 print_file_info(f.file, db->files[i]);
387 }
388 fprintf(f.file,
389 "\n"
390 "Copyright (C) ");
391 if(db->copyright.firstyear && db->copyright.firstyear < (1900 + tm.tm_year))
392 fprintf(f.file, "%u-", db->copyright.firstyear);
393 fprintf(f.file, "%u", 1900 + tm.tm_year);
394 if(db->copyright.authorsnum) {
395 fprintf(f.file, " by the following authors:");
396 for(i = 0; i < db->copyright.authorsnum; ++i) {
397 fprintf(f.file, "\n- ");
398 if(db->copyright.authors[i]->name)
399 fprintf(f.file, "%s", db->copyright.authors[i]->name);
400 if(db->copyright.authors[i]->email)
401 fprintf(f.file, " <%s>", db->copyright.authors[i]->email);
402 if(db->copyright.authors[i]->nicknamesnum) {
403 for(j = 0; j < db->copyright.authors[i]->nicknamesnum; ++j) {
404 fprintf(f.file, "%s%s", (j ? ", " : " ("), db->copyright.authors[i]->nicknames[j]);
405 }
406 fprintf(f.file, ")");
407 }
408 }
409 }
410 fprintf(f.file, "\n");
411 if(db->copyright.license)
412 fprintf(f.file, "\n%s\n", db->copyright.license);
413 fprintf(f.file, "*/\n\n\n");
414 }
415
416 int main(int argc, char **argv) {
417 char *file;
418 struct rnndb *db;
419 int i, j;
420
421 if (argc < 2) {
422 fprintf(stderr, "Usage:\n\theadergen database-file\n");
423 exit(1);
424 }
425
426 if ((argc >= 3) && !strcmp(argv[1], "--no-asserts")) {
427 no_asserts = true;
428 file = argv[2];
429 } else {
430 file = argv[1];
431 }
432
433 rnn_init();
434 db = rnn_newdb();
435 rnn_parsefile (db, file);
436 rnn_prepdb (db);
437 for(i = 0; i < db->filesnum; ++i) {
438 char *dstname = malloc(strlen(db->files[i]) + 3);
439 char *pretty;
440 strcpy(dstname, db->files[i]);
441 strcat(dstname, ".h");
442 struct fout f = { db->files[i], fopen(dstname, "w") };
443 if (!f.file) {
444 perror(dstname);
445 exit(1);
446 }
447 free(dstname);
448 pretty = strrchr(f.name, '/');
449 if (pretty)
450 pretty += 1;
451 else
452 pretty = f.name;
453 f.guard = strdup(pretty);
454 for (j = 0; j < strlen(f.guard); j++)
455 if (isalnum(f.guard[j]))
456 f.guard[j] = toupper(f.guard[j]);
457 else
458 f.guard[j] = '_';
459 ADDARRAY(fouts, f);
460 printhead(f, db);
461 }
462
463 for (i = 0; i < db->enumsnum; i++) {
464 FILE *dst = NULL;
465 int j;
466 for (j = 0; j < db->enums[i]->valsnum; j++) {
467 if (!dst) {
468 dst = findfout(db->enums[i]->vals[j]->file);
469 fprintf(dst, "enum %s {\n", db->enums[i]->name);
470 }
471 if (0xffff0000 & db->enums[i]->vals[j]->value)
472 fprintf(dst, "\t%s = 0x%08lx,\n", db->enums[i]->vals[j]->name,
473 db->enums[i]->vals[j]->value);
474 else
475 fprintf(dst, "\t%s = %lu,\n", db->enums[i]->vals[j]->name,
476 db->enums[i]->vals[j]->value);
477 }
478 if (dst) {
479 fprintf(dst, "};\n\n");
480 }
481 }
482 for (i = 0; i < db->bitsetsnum; i++) {
483 if (db->bitsets[i]->isinline)
484 continue;
485 int j;
486 for (j = 0; j < db->bitsets[i]->bitfieldsnum; j++)
487 printbitfield (db->bitsets[i]->bitfields[j], 0);
488 }
489 for (i = 0; i < db->domainsnum; i++) {
490 if (db->domains[i]->size)
491 printdef (db->domains[i]->fullname, "SIZE", 0, db->domains[i]->size, db->domains[i]->file);
492 int j;
493 for (j = 0; j < db->domains[i]->subelemsnum; j++) {
494 printdelem(db->domains[i]->subelems[j], 0);
495 }
496 }
497 for(i = 0; i < foutsnum; ++i) {
498 fprintf (fouts[i].file, "\n#endif /* %s */\n", fouts[i].guard);
499 }
500 return db->estatus;
501 }