Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/freedreno/isa/decode.c
4564 views
1
/*
2
* Copyright © 2020 Google, Inc.
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
13
* Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
* SOFTWARE.
22
*/
23
24
#include <assert.h>
25
#include <inttypes.h>
26
#include <stdbool.h>
27
#include <stdint.h>
28
#include <stdio.h>
29
#include <stdlib.h>
30
#include <string.h>
31
32
#include "util/bitset.h"
33
#include "util/compiler.h"
34
#include "util/half_float.h"
35
#include "util/hash_table.h"
36
#include "util/ralloc.h"
37
#include "util/u_debug.h"
38
#include "util/u_math.h"
39
40
#include "decode.h"
41
#include "isa.h"
42
43
/**
44
* The set of leaf node bitsets in the bitset hiearchy which defines all
45
* the possible instructions.
46
*
47
* TODO maybe we want to pass this in as parameter so this same decoder
48
* can work with multiple different instruction sets.
49
*/
50
extern const struct isa_bitset *__instruction[];
51
52
struct decode_state;
53
54
/**
55
* Decode scope. When parsing a field that is itself a bitset, we push a
56
* new scope to the stack. A nested bitset is allowed to resolve fields
57
* from an enclosing scope (needed, for example, to decode src register
58
* bitsets, where half/fullness is determined by fields outset if bitset
59
* in the instruction containing the bitset.
60
*
61
* But the field being resolved could be a derived field, or different
62
* depending on an override at a higher level of the stack, requiring
63
* expression evaluation which could in turn reference variables which
64
* triggers a recursive field lookup. But those lookups should not start
65
* from the top of the stack, but instead the current stack level. This
66
* prevents a field from accidentally resolving to different values
67
* depending on the starting point of the lookup. (Not only causing
68
* confusion, but this is behavior we don't want to depend on if we
69
* wanted to optimize things by caching field lookup results.)
70
*/
71
struct decode_scope {
72
/**
73
* Enclosing scope
74
*/
75
struct decode_scope *parent;
76
77
/**
78
* Current bitset value being decoded
79
*/
80
uint64_t val;
81
82
/**
83
* Current bitset.
84
*/
85
const struct isa_bitset *bitset;
86
87
/**
88
* Field name remapping.
89
*/
90
const struct isa_field_params *params;
91
92
/**
93
* Pointer back to decode state, for convenience.
94
*/
95
struct decode_state *state;
96
97
/**
98
* Cache expression evaluation results. Expressions for overrides can
99
* be repeatedly evaluated for each field being resolved. And each
100
* field reference to a derived field (potentially from another expr)
101
* would require re-evaluation. But for a given scope, each evaluation
102
* of an expression gives the same result. So we can cache to speed
103
* things up.
104
*
105
* TODO we could maybe be clever and assign a unique idx to each expr
106
* and use a direct lookup table? Would be a bit more clever if it was
107
* smart enough to allow unrelated expressions that are never involved
108
* in a given scope to have overlapping cache lookup idx's.
109
*/
110
struct hash_table *cache;
111
};
112
113
/**
114
* Current decode state
115
*/
116
struct decode_state {
117
const struct isa_decode_options *options;
118
FILE *out;
119
120
/**
121
* Current instruction being decoded:
122
*/
123
unsigned n;
124
125
/**
126
* Number of instructions being decoded
127
*/
128
unsigned num_instr;
129
130
/**
131
* Bitset of instructions that are branch targets (if options->branch_labels
132
* is enabled)
133
*/
134
BITSET_WORD *branch_targets;
135
136
/**
137
* We allow a limited amount of expression evaluation recursion, but
138
* not recursive evaluation of any given expression, to prevent infinite
139
* recursion.
140
*/
141
int expr_sp;
142
isa_expr_t expr_stack[8];
143
144
/**
145
* Current topmost/innermost level of scope used for decoding fields,
146
* including derived fields which may in turn rely on decoding other
147
* fields, potentially from a lower/out level in the stack.
148
*/
149
struct decode_scope *scope;
150
151
/**
152
* A small fixed upper limit on # of decode errors to capture per-
153
* instruction seems reasonable.
154
*/
155
unsigned num_errors;
156
char *errors[4];
157
};
158
159
static void display(struct decode_scope *scope);
160
static void decode_error(struct decode_state *state, const char *fmt, ...) _util_printf_format(2,3);
161
162
static void
163
decode_error(struct decode_state *state, const char *fmt, ...)
164
{
165
if (!state->options->show_errors) {
166
return;
167
}
168
169
if (state->num_errors == ARRAY_SIZE(state->errors)) {
170
/* too many errors, bail */
171
return;
172
}
173
174
va_list ap;
175
va_start(ap, fmt);
176
vasprintf(&state->errors[state->num_errors++], fmt, ap);
177
va_end(ap);
178
}
179
180
static unsigned
181
flush_errors(struct decode_state *state)
182
{
183
unsigned num_errors = state->num_errors;
184
if (num_errors > 0)
185
fprintf(state->out, "\t; ");
186
for (unsigned i = 0; i < num_errors; i++) {
187
fprintf(state->out, "%s%s", (i > 0) ? ", " : "", state->errors[i]);
188
free(state->errors[i]);
189
}
190
state->num_errors = 0;
191
return num_errors;
192
}
193
194
195
static bool
196
push_expr(struct decode_state *state, isa_expr_t expr)
197
{
198
for (int i = state->expr_sp - 1; i > 0; i--) {
199
if (state->expr_stack[i] == expr) {
200
return false;
201
}
202
}
203
state->expr_stack[state->expr_sp++] = expr;
204
return true;
205
}
206
207
static void
208
pop_expr(struct decode_state *state)
209
{
210
assert(state->expr_sp > 0);
211
state->expr_sp--;
212
}
213
214
static struct decode_scope *
215
push_scope(struct decode_state *state, const struct isa_bitset *bitset, uint64_t val)
216
{
217
struct decode_scope *scope = rzalloc_size(state, sizeof(*scope));
218
219
scope->val = val;
220
scope->bitset = bitset;
221
scope->parent = state->scope;
222
scope->state = state;
223
224
state->scope = scope;
225
226
return scope;
227
}
228
229
static void
230
pop_scope(struct decode_scope *scope)
231
{
232
assert(scope->state->scope == scope); /* must be top of stack */
233
234
scope->state->scope = scope->parent;
235
ralloc_free(scope);
236
}
237
238
/**
239
* Evaluate an expression, returning it's resulting value
240
*/
241
static uint64_t
242
evaluate_expr(struct decode_scope *scope, isa_expr_t expr)
243
{
244
if (scope->cache) {
245
struct hash_entry *entry = _mesa_hash_table_search(scope->cache, expr);
246
if (entry) {
247
return *(uint64_t *)entry->data;
248
}
249
} else {
250
scope->cache = _mesa_pointer_hash_table_create(scope);
251
}
252
253
if (!push_expr(scope->state, expr))
254
return 0;
255
256
uint64_t ret = expr(scope);
257
258
pop_expr(scope->state);
259
260
uint64_t *retp = ralloc_size(scope->cache, sizeof(*retp));
261
*retp = ret;
262
_mesa_hash_table_insert(scope->cache, expr, retp);
263
264
return ret;
265
}
266
267
/**
268
* Find the bitset in NULL terminated bitset hiearchy root table which
269
* matches against 'val'
270
*/
271
static const struct isa_bitset *
272
find_bitset(struct decode_state *state, const struct isa_bitset **bitsets,
273
uint64_t val)
274
{
275
const struct isa_bitset *match = NULL;
276
for (int n = 0; bitsets[n]; n++) {
277
if (state->options->gpu_id > bitsets[n]->gen.max)
278
continue;
279
if (state->options->gpu_id < bitsets[n]->gen.min)
280
continue;
281
282
uint64_t m = (val & bitsets[n]->mask) & ~bitsets[n]->dontcare;
283
284
if (m != bitsets[n]->match) {
285
continue;
286
}
287
288
/* We should only have exactly one match
289
*
290
* TODO more complete/formal way to validate that any given
291
* bit pattern will only have a single match?
292
*/
293
if (match) {
294
decode_error(state, "bitset conflict: %s vs %s", match->name,
295
bitsets[n]->name);
296
return NULL;
297
}
298
299
match = bitsets[n];
300
}
301
302
if (match && (match->dontcare & val)) {
303
decode_error(state, "dontcare bits in %s: %"PRIx64,
304
match->name, (match->dontcare & val));
305
}
306
307
return match;
308
}
309
310
static const struct isa_field *
311
find_field(struct decode_scope *scope, const struct isa_bitset *bitset,
312
const char *name)
313
{
314
for (unsigned i = 0; i < bitset->num_cases; i++) {
315
const struct isa_case *c = bitset->cases[i];
316
317
if (c->expr) {
318
struct decode_state *state = scope->state;
319
320
/* When resolving a field for evaluating an expression,
321
* temporarily assume the expression evaluates to true.
322
* This allows <override/>'s to speculatively refer to
323
* fields defined within the override:
324
*/
325
isa_expr_t cur_expr = NULL;
326
if (state->expr_sp > 0)
327
cur_expr = state->expr_stack[state->expr_sp - 1];
328
if ((cur_expr != c->expr) && !evaluate_expr(scope, c->expr))
329
continue;
330
}
331
332
for (unsigned i = 0; i < c->num_fields; i++) {
333
if (!strcmp(name, c->fields[i].name)) {
334
return &c->fields[i];
335
}
336
}
337
}
338
339
if (bitset->parent) {
340
const struct isa_field *f = find_field(scope, bitset->parent, name);
341
if (f) {
342
return f;
343
}
344
}
345
346
return NULL;
347
}
348
349
static uint64_t
350
extract_field(struct decode_scope *scope, const struct isa_field *field)
351
{
352
uint64_t val = scope->val;
353
val = (val >> field->low) & ((1ul << (1 + field->high - field->low)) - 1);
354
return val;
355
}
356
357
/**
358
* Find the display template for a given bitset, recursively searching
359
* parents in the bitset hierarchy.
360
*/
361
static const char *
362
find_display(struct decode_scope *scope, const struct isa_bitset *bitset)
363
{
364
for (unsigned i = 0; i < bitset->num_cases; i++) {
365
const struct isa_case *c = bitset->cases[i];
366
if (c->expr && !evaluate_expr(scope, c->expr))
367
continue;
368
/* since this is the chosen case, it seems like a good place
369
* to check asserted bits:
370
*/
371
for (unsigned j = 0; j < c->num_fields; j++) {
372
if (c->fields[j].type == TYPE_ASSERT) {
373
const struct isa_field *f = &c->fields[j];
374
uint64_t val = extract_field(scope, f);
375
if (val != f->val) {
376
decode_error(scope->state, "WARNING: unexpected "
377
"bits[%u:%u] in %s: 0x%"PRIx64" vs 0x%"PRIx64,
378
f->low, f->high, bitset->name,
379
val, f->val);
380
}
381
}
382
}
383
if (!c->display)
384
continue;
385
return c->display;
386
}
387
388
/**
389
* If we didn't find something check up the bitset hierarchy.
390
*/
391
if (bitset->parent) {
392
return find_display(scope, bitset->parent);
393
}
394
395
return NULL;
396
}
397
398
/**
399
* Decode a field that is itself another bitset type
400
*/
401
static void
402
display_bitset_field(struct decode_scope *scope, const struct isa_field *field, uint64_t val)
403
{
404
const struct isa_bitset *b = find_bitset(scope->state, field->bitsets, val);
405
if (!b) {
406
decode_error(scope->state, "no match: FIELD: '%s.%s': 0x%"PRIx64,
407
scope->bitset->name, field->name, val);
408
return;
409
}
410
411
struct decode_scope *nested_scope =
412
push_scope(scope->state, b, val);
413
nested_scope->params = field->params;
414
display(nested_scope);
415
pop_scope(nested_scope);
416
}
417
418
static void
419
display_enum_field(struct decode_scope *scope, const struct isa_field *field, uint64_t val)
420
{
421
FILE *out = scope->state->out;
422
423
const struct isa_enum *e = field->enums;
424
for (unsigned i = 0; i < e->num_values; i++) {
425
if (e->values[i].val == val) {
426
fprintf(out, "%s", e->values[i].display);
427
return;
428
}
429
}
430
431
fprintf(out, "%u", (unsigned)val);
432
}
433
434
static const struct isa_field *
435
resolve_field(struct decode_scope *scope, const char *field_name, uint64_t *valp)
436
{
437
if (!scope) {
438
/* We've reached the bottom of the stack! */
439
return NULL;
440
}
441
442
const struct isa_field *field =
443
find_field(scope, scope->bitset, field_name);
444
445
if (!field && scope->params) {
446
for (unsigned i = 0; i < scope->params->num_params; i++) {
447
if (!strcmp(field_name, scope->params->params[i].as)) {
448
const char *param_name = scope->params->params[i].name;
449
return resolve_field(scope->parent, param_name, valp);
450
}
451
}
452
}
453
454
if (!field) {
455
return NULL;
456
}
457
458
/* extract out raw field value: */
459
if (field->expr) {
460
*valp = evaluate_expr(scope, field->expr);
461
} else {
462
*valp = extract_field(scope, field);
463
}
464
465
return field;
466
}
467
468
/* This is also used from generated expr functions */
469
uint64_t
470
isa_decode_field(struct decode_scope *scope, const char *field_name)
471
{
472
uint64_t val;
473
const struct isa_field *field = resolve_field(scope, field_name, &val);
474
if (!field) {
475
decode_error(scope->state, "no field '%s'", field_name);
476
return 0;
477
}
478
479
return val;
480
}
481
482
static void
483
display_field(struct decode_scope *scope, const char *field_name)
484
{
485
const struct isa_decode_options *options = scope->state->options;
486
487
/* Special case 'NAME' maps to instruction/bitset name: */
488
if (!strcmp("NAME", field_name)) {
489
if (options->field_cb) {
490
options->field_cb(options->cbdata, field_name, &(struct isa_decode_value){
491
.str = scope->bitset->name,
492
});
493
}
494
495
fprintf(scope->state->out, "%s", scope->bitset->name);
496
497
return;
498
}
499
500
uint64_t val;
501
const struct isa_field *field = resolve_field(scope, field_name, &val);
502
if (!field) {
503
decode_error(scope->state, "no field '%s'", field_name);
504
return;
505
}
506
507
if (options->field_cb) {
508
options->field_cb(options->cbdata, field_name, &(struct isa_decode_value){
509
.num = val,
510
});
511
}
512
513
unsigned width = 1 + field->high - field->low;
514
FILE *out = scope->state->out;
515
516
switch (field->type) {
517
/* Basic types: */
518
case TYPE_BRANCH:
519
if (scope->state->options->branch_labels) {
520
int offset = util_sign_extend(val, width) + scope->state->n;
521
if (offset < scope->state->num_instr) {
522
fprintf(out, "l%d", offset);
523
BITSET_SET(scope->state->branch_targets, offset);
524
break;
525
}
526
}
527
FALLTHROUGH;
528
case TYPE_INT:
529
fprintf(out, "%"PRId64, util_sign_extend(val, width));
530
break;
531
case TYPE_UINT:
532
fprintf(out, "%"PRIu64, val);
533
break;
534
case TYPE_HEX:
535
// TODO format # of digits based on field width?
536
fprintf(out, "%"PRIx64, val);
537
break;
538
case TYPE_OFFSET:
539
if (val != 0) {
540
fprintf(out, "%+"PRId64, util_sign_extend(val, width));
541
}
542
break;
543
case TYPE_UOFFSET:
544
if (val != 0) {
545
fprintf(out, "+%"PRIu64, val);
546
}
547
break;
548
case TYPE_FLOAT:
549
if (width == 16) {
550
fprintf(out, "%f", _mesa_half_to_float(val));
551
} else {
552
assert(width == 32);
553
fprintf(out, "%f", uif(val));
554
}
555
break;
556
case TYPE_BOOL:
557
if (field->display) {
558
if (val) {
559
fprintf(out, "%s", field->display);
560
}
561
} else {
562
fprintf(out, "%u", (unsigned)val);
563
}
564
break;
565
case TYPE_ENUM:
566
display_enum_field(scope, field, val);
567
break;
568
569
case TYPE_ASSERT:
570
/* assert fields are not for display */
571
assert(0);
572
break;
573
574
/* For fields that are decoded with another bitset hierarchy: */
575
case TYPE_BITSET:
576
display_bitset_field(scope, field, val);
577
break;
578
default:
579
decode_error(scope->state, "Bad field type: %d (%s)",
580
field->type, field->name);
581
}
582
}
583
584
static void
585
display(struct decode_scope *scope)
586
{
587
const struct isa_bitset *bitset = scope->bitset;
588
const char *display = find_display(scope, bitset);
589
590
if (!display) {
591
decode_error(scope->state, "%s: no display template", bitset->name);
592
return;
593
}
594
595
const char *p = display;
596
597
while (*p != '\0') {
598
if (*p == '{') {
599
const char *e = ++p;
600
while (*e != '}') {
601
e++;
602
}
603
604
char *field_name = strndup(p, e-p);
605
display_field(scope, field_name);
606
free(field_name);
607
608
p = e;
609
} else {
610
fputc(*p, scope->state->out);
611
}
612
p++;
613
}
614
}
615
616
static void
617
decode(struct decode_state *state, void *bin, int sz)
618
{
619
uint64_t *instrs = bin;
620
unsigned errors = 0; /* number of consecutive unmatched instructions */
621
622
for (state->n = 0; state->n < state->num_instr; state->n++) {
623
uint64_t instr = instrs[state->n];
624
625
if (state->options->max_errors && (errors > state->options->max_errors)) {
626
break;
627
}
628
629
if (state->options->branch_labels &&
630
BITSET_TEST(state->branch_targets, state->n)) {
631
if (state->options->instr_cb) {
632
state->options->instr_cb(state->options->cbdata,
633
state->n, instr);
634
}
635
fprintf(state->out, "l%d:\n", state->n);
636
}
637
638
if (state->options->instr_cb) {
639
state->options->instr_cb(state->options->cbdata, state->n, instr);
640
}
641
642
const struct isa_bitset *b = find_bitset(state, __instruction, instr);
643
if (!b) {
644
fprintf(state->out, "no match: %016"PRIx64"\n", instr);
645
errors++;
646
continue;
647
}
648
649
struct decode_scope *scope = push_scope(state, b, instr);
650
651
display(scope);
652
if (flush_errors(state)) {
653
errors++;
654
} else {
655
errors = 0;
656
}
657
fprintf(state->out, "\n");
658
659
pop_scope(scope);
660
661
if (state->options->stop) {
662
break;
663
}
664
}
665
}
666
667
void
668
isa_decode(void *bin, int sz, FILE *out, const struct isa_decode_options *options)
669
{
670
const struct isa_decode_options default_options = {
671
.branch_labels = options ? options->branch_labels : false
672
};
673
struct decode_state *state;
674
675
if (!options)
676
options = &default_options;
677
678
util_cpu_detect(); /* needed for _mesa_half_to_float() */
679
680
state = rzalloc_size(NULL, sizeof(*state));
681
state->options = options;
682
state->num_instr = sz / 8;
683
684
if (state->options->branch_labels) {
685
state->branch_targets = rzalloc_size(state,
686
sizeof(BITSET_WORD) * BITSET_WORDS(state->num_instr));
687
688
/* Do a pre-pass to find all the branch targets: */
689
state->out = fopen("/dev/null", "w");
690
state->options = &default_options; /* skip hooks for prepass */
691
decode(state, bin, sz);
692
fclose(state->out);
693
if (options) {
694
state->options = options;
695
}
696
}
697
698
state->out = out;
699
700
decode(state, bin, sz);
701
702
ralloc_free(state);
703
}
704
705