Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/panfrost/midgard/disassemble.c
4564 views
1
/* Author(s):
2
* Connor Abbott
3
* Alyssa Rosenzweig
4
*
5
* Copyright (c) 2013 Connor Abbott ([email protected])
6
* Copyright (c) 2018 Alyssa Rosenzweig ([email protected])
7
* Copyright (C) 2019-2020 Collabora, Ltd.
8
*
9
* Permission is hereby granted, free of charge, to any person obtaining a copy
10
* of this software and associated documentation files (the "Software"), to deal
11
* in the Software without restriction, including without limitation the rights
12
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
* copies of the Software, and to permit persons to whom the Software is
14
* furnished to do so, subject to the following conditions:
15
*
16
* The above copyright notice and this permission notice shall be included in
17
* all copies or substantial portions of the 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 THE
22
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
* THE SOFTWARE.
26
*/
27
28
#include <stdio.h>
29
#include <stdint.h>
30
#include <stdlib.h>
31
#include <assert.h>
32
#include <inttypes.h>
33
#include <ctype.h>
34
#include <string.h>
35
#include "midgard.h"
36
#include "midgard_ops.h"
37
#include "midgard_quirks.h"
38
#include "disassemble.h"
39
#include "helpers.h"
40
#include "util/bitscan.h"
41
#include "util/half_float.h"
42
#include "util/u_math.h"
43
44
#define DEFINE_CASE(define, str) case define: { fprintf(fp, str); break; }
45
46
/* These are not mapped to hardware values, they just represent the possible
47
* implicit arg modifiers that some midgard opcodes have, which can be decoded
48
* from the opcodes via midgard_{alu,ldst,tex}_special_arg_mod() */
49
typedef enum {
50
midgard_arg_mod_none = 0,
51
midgard_arg_mod_inv,
52
midgard_arg_mod_x2,
53
} midgard_special_arg_mod;
54
55
static unsigned *midg_tags;
56
static bool is_instruction_int = false;
57
58
/* Stats */
59
60
static struct midgard_disasm_stats midg_stats;
61
62
/* Transform an expanded writemask (duplicated 8-bit format) into its condensed
63
* form (one bit per component) */
64
65
static inline unsigned
66
condense_writemask(unsigned expanded_mask,
67
unsigned bits_per_component)
68
{
69
if (bits_per_component == 8) {
70
/* Duplicate every bit to go from 8 to 16-channel wrmask */
71
unsigned omask = 0;
72
73
for (unsigned i = 0; i < 8; ++i) {
74
if (expanded_mask & (1 << i))
75
omask |= (3 << (2 * i));
76
}
77
78
return omask;
79
}
80
81
unsigned slots_per_component = bits_per_component / 16;
82
unsigned max_comp = (16 * 8) / bits_per_component;
83
unsigned condensed_mask = 0;
84
85
for (unsigned i = 0; i < max_comp; i++) {
86
if (expanded_mask & (1 << (i * slots_per_component)))
87
condensed_mask |= (1 << i);
88
}
89
90
return condensed_mask;
91
}
92
93
static void
94
print_alu_opcode(FILE *fp, midgard_alu_op op)
95
{
96
if (alu_opcode_props[op].name)
97
fprintf(fp, "%s", alu_opcode_props[op].name);
98
else
99
fprintf(fp, "alu_op_%02X", op);
100
101
/* For constant analysis */
102
is_instruction_int = midgard_is_integer_op(op);
103
}
104
105
static void
106
print_ld_st_opcode(FILE *fp, midgard_load_store_op op)
107
{
108
if (load_store_opcode_props[op].name)
109
fprintf(fp, "%s", load_store_opcode_props[op].name);
110
else
111
fprintf(fp, "ldst_op_%02X", op);
112
}
113
114
static void
115
validate_sampler_type(enum mali_texture_op op, enum mali_sampler_type sampler_type)
116
{
117
if (op == midgard_tex_op_mov || op == midgard_tex_op_barrier)
118
assert(sampler_type == 0);
119
else
120
assert(sampler_type > 0);
121
}
122
123
static void
124
validate_expand_mode(midgard_src_expand_mode expand_mode,
125
midgard_reg_mode reg_mode)
126
{
127
switch (expand_mode) {
128
case midgard_src_passthrough:
129
break;
130
131
case midgard_src_rep_low:
132
assert(reg_mode == midgard_reg_mode_8 ||
133
reg_mode == midgard_reg_mode_16);
134
break;
135
136
case midgard_src_rep_high:
137
assert(reg_mode == midgard_reg_mode_8 ||
138
reg_mode == midgard_reg_mode_16);
139
break;
140
141
case midgard_src_swap:
142
assert(reg_mode == midgard_reg_mode_8 ||
143
reg_mode == midgard_reg_mode_16);
144
break;
145
146
case midgard_src_expand_low:
147
assert(reg_mode != midgard_reg_mode_8);
148
break;
149
150
case midgard_src_expand_high:
151
assert(reg_mode != midgard_reg_mode_8);
152
break;
153
154
case midgard_src_expand_low_swap:
155
assert(reg_mode == midgard_reg_mode_16);
156
break;
157
158
case midgard_src_expand_high_swap:
159
assert(reg_mode == midgard_reg_mode_16);
160
break;
161
162
default:
163
unreachable("Invalid expand mode");
164
break;
165
}
166
}
167
168
/* For static analysis to ensure all registers are written at least once before
169
* use along the source code path (TODO: does this break done for complex CF?)
170
*/
171
172
uint16_t midg_ever_written = 0;
173
174
static void
175
print_alu_reg(FILE *fp, unsigned reg, bool is_write)
176
{
177
unsigned uniform_reg = 23 - reg;
178
bool is_uniform = false;
179
180
/* For r8-r15, it could be a work or uniform. We distinguish based on
181
* the fact work registers are ALWAYS written before use, but uniform
182
* registers are NEVER written before use. */
183
184
if ((reg >= 8 && reg < 16) && !(midg_ever_written & (1 << reg)))
185
is_uniform = true;
186
187
/* r16-r23 are always uniform */
188
189
if (reg >= 16 && reg <= 23)
190
is_uniform = true;
191
192
/* Update the uniform count appropriately */
193
194
if (is_uniform)
195
midg_stats.uniform_count =
196
MAX2(uniform_reg + 1, midg_stats.uniform_count);
197
198
if (reg == REGISTER_UNUSED || reg == REGISTER_UNUSED + 1)
199
fprintf(fp, "TMP%u", reg - REGISTER_UNUSED);
200
else if (reg == REGISTER_TEXTURE_BASE || reg == REGISTER_TEXTURE_BASE + 1)
201
fprintf(fp, "%s%u", is_write ? "AT" : "TA", reg - REGISTER_TEXTURE_BASE);
202
else if (reg == REGISTER_LDST_BASE || reg == REGISTER_LDST_BASE + 1)
203
fprintf(fp, "AL%u", reg - REGISTER_LDST_BASE);
204
else if (is_uniform)
205
fprintf(fp, "U%u", uniform_reg);
206
else if (reg == 31 && !is_write)
207
fprintf(fp, "PC_SP");
208
else
209
fprintf(fp, "R%u", reg);
210
}
211
212
static void
213
print_ldst_write_reg(FILE *fp, unsigned reg)
214
{
215
switch (reg) {
216
case 26:
217
case 27:
218
fprintf(fp, "AL%u", reg - REGISTER_LDST_BASE);
219
break;
220
case 28:
221
case 29:
222
fprintf(fp, "AT%u", reg - REGISTER_TEXTURE_BASE);
223
break;
224
case 31:
225
fprintf(fp, "PC_SP");
226
break;
227
default:
228
fprintf(fp, "R%d", reg);
229
break;
230
}
231
}
232
233
static void
234
print_ldst_read_reg(FILE *fp, unsigned reg)
235
{
236
switch (reg) {
237
case 0:
238
case 1:
239
fprintf(fp, "AL%u", reg);
240
break;
241
case 2:
242
fprintf(fp, "PC_SP");
243
break;
244
case 3:
245
fprintf(fp, "LOCAL_STORAGE_PTR");
246
break;
247
case 4:
248
fprintf(fp, "LOCAL_THREAD_ID");
249
break;
250
case 5:
251
fprintf(fp, "GROUP_ID");
252
break;
253
case 6:
254
fprintf(fp, "GLOBAL_THREAD_ID");
255
break;
256
case 7:
257
fprintf(fp, "0");
258
break;
259
default:
260
unreachable("Invalid load/store register read");
261
}
262
}
263
264
static void
265
print_tex_reg(FILE *fp, unsigned reg, bool is_write)
266
{
267
char *str = is_write ? "TA" : "AT";
268
int select = reg & 1;
269
270
switch (reg) {
271
case 0:
272
case 1:
273
fprintf(fp, "R%d", select);
274
break;
275
case 26:
276
case 27:
277
fprintf(fp, "AL%d", select);
278
break;
279
case 28:
280
case 29:
281
fprintf(fp, "%s%d", str, select);
282
break;
283
default:
284
unreachable("Invalid texture register");
285
}
286
}
287
288
289
static char *outmod_names_float[4] = {
290
"",
291
".clamp_0_inf",
292
".clamp_m1_1",
293
".clamp_0_1"
294
};
295
296
static char *outmod_names_int[4] = {
297
".ssat",
298
".usat",
299
".keeplo",
300
".keephi"
301
};
302
303
static char *srcmod_names_int[4] = {
304
".sext",
305
".zext",
306
".replicate",
307
".lshift",
308
};
309
310
static char *argmod_names[3] = {
311
"",
312
".inv",
313
".x2",
314
};
315
316
static char *index_format_names[4] = {
317
"",
318
".u64",
319
".u32",
320
".s32"
321
};
322
323
static void
324
print_outmod(FILE *fp, unsigned outmod, bool is_int)
325
{
326
fprintf(fp, "%s", is_int ? outmod_names_int[outmod] :
327
outmod_names_float[outmod]);
328
}
329
330
static void
331
print_alu_outmod(FILE *fp, unsigned outmod, bool is_int, bool half)
332
{
333
if (is_int && !half) {
334
assert(outmod == midgard_outmod_keeplo);
335
return;
336
}
337
338
if (!is_int && half)
339
fprintf(fp, ".shrink");
340
341
print_outmod(fp, outmod, is_int);
342
}
343
344
/* arg == 0 (dest), arg == 1 (src1), arg == 2 (src2) */
345
static midgard_special_arg_mod
346
midgard_alu_special_arg_mod(midgard_alu_op op, unsigned arg) {
347
midgard_special_arg_mod mod = midgard_arg_mod_none;
348
349
switch (op) {
350
case midgard_alu_op_ishladd:
351
case midgard_alu_op_ishlsub:
352
if (arg == 1) mod = midgard_arg_mod_x2;
353
break;
354
355
default:
356
break;
357
}
358
359
return mod;
360
}
361
362
static void
363
print_quad_word(FILE *fp, uint32_t *words, unsigned tabs)
364
{
365
unsigned i;
366
367
for (i = 0; i < 4; i++)
368
fprintf(fp, "0x%08X%s ", words[i], i == 3 ? "" : ",");
369
370
fprintf(fp, "\n");
371
}
372
373
static const char components[16] = "xyzwefghijklmnop";
374
375
static int
376
bits_for_mode(midgard_reg_mode mode)
377
{
378
switch (mode) {
379
case midgard_reg_mode_8:
380
return 8;
381
case midgard_reg_mode_16:
382
return 16;
383
case midgard_reg_mode_32:
384
return 32;
385
case midgard_reg_mode_64:
386
return 64;
387
default:
388
unreachable("Invalid reg mode");
389
return 0;
390
}
391
}
392
393
static int
394
bits_for_mode_halved(midgard_reg_mode mode, bool half)
395
{
396
unsigned bits = bits_for_mode(mode);
397
398
if (half)
399
bits >>= 1;
400
401
return bits;
402
}
403
404
static void
405
print_vec_selectors_64(FILE *fp, unsigned swizzle,
406
midgard_reg_mode reg_mode,
407
midgard_src_expand_mode expand_mode,
408
unsigned selector_offset, uint8_t mask)
409
{
410
bool expands = INPUT_EXPANDS(expand_mode);
411
412
unsigned comp_skip = expands ? 1 : 2;
413
unsigned mask_bit = 0;
414
for (unsigned i = selector_offset; i < 4; i += comp_skip, mask_bit += 4) {
415
if (!(mask & (1 << mask_bit))) continue;
416
417
unsigned a = (swizzle >> (i * 2)) & 3;
418
419
if (INPUT_EXPANDS(expand_mode)) {
420
fprintf(fp, "%c", components[a]);
421
continue;
422
}
423
424
unsigned b = (swizzle >> ((i+1) * 2)) & 3;
425
426
/* Normally we're adjacent, but if there's an issue,
427
* don't make it ambiguous */
428
429
if (b == a + 1)
430
fprintf(fp, "%c", a >> 1 ? 'Y' : 'X');
431
else
432
fprintf(fp, "[%c%c]", components[a], components[b]);
433
}
434
}
435
436
static void
437
print_vec_selectors(FILE *fp, unsigned swizzle,
438
midgard_reg_mode reg_mode,
439
unsigned selector_offset, uint8_t mask,
440
unsigned *mask_offset)
441
{
442
assert(reg_mode != midgard_reg_mode_64);
443
444
unsigned mask_skip = MAX2(bits_for_mode(reg_mode) / 16, 1);
445
446
bool is_vec16 = reg_mode == midgard_reg_mode_8;
447
448
for (unsigned i = 0; i < 4; i++, *mask_offset += mask_skip) {
449
if (!(mask & (1 << *mask_offset))) continue;
450
451
unsigned c = (swizzle >> (i * 2)) & 3;
452
453
/* Vec16 has two components per swizzle selector. */
454
if (is_vec16)
455
c *= 2;
456
457
c += selector_offset;
458
459
fprintf(fp, "%c", components[c]);
460
if (is_vec16)
461
fprintf(fp, "%c", components[c+1]);
462
}
463
}
464
465
static void
466
print_vec_swizzle(FILE *fp, unsigned swizzle,
467
midgard_src_expand_mode expand,
468
midgard_reg_mode mode,
469
uint8_t mask)
470
{
471
unsigned bits = bits_for_mode_halved(mode, INPUT_EXPANDS(expand));
472
473
/* Swizzle selectors are divided in two halves that are always
474
* mirrored, the only difference is the starting component offset.
475
* The number represents an offset into the components[] array. */
476
unsigned first_half = 0;
477
unsigned second_half = (128 / bits) / 2; /* only used for 8 and 16-bit */
478
479
switch (expand) {
480
case midgard_src_passthrough:
481
if (swizzle == 0xE4) return; /* identity swizzle */
482
break;
483
484
case midgard_src_expand_low:
485
second_half /= 2;
486
break;
487
488
case midgard_src_expand_high:
489
first_half = second_half;
490
second_half += second_half / 2;
491
break;
492
493
/* The rest of the cases are only used for 8 and 16-bit */
494
495
case midgard_src_rep_low:
496
second_half = 0;
497
break;
498
499
case midgard_src_rep_high:
500
first_half = second_half;
501
break;
502
503
case midgard_src_swap:
504
first_half = second_half;
505
second_half = 0;
506
break;
507
508
case midgard_src_expand_low_swap:
509
first_half = second_half / 2;
510
second_half = 0;
511
break;
512
513
case midgard_src_expand_high_swap:
514
first_half = second_half + second_half / 2;
515
break;
516
517
default:
518
unreachable("Invalid expand mode");
519
break;
520
}
521
522
fprintf(fp, ".");
523
524
/* Vec2 are weird so we use a separate function to simplify things. */
525
if (mode == midgard_reg_mode_64) {
526
print_vec_selectors_64(fp, swizzle, mode, expand, first_half, mask);
527
return;
528
}
529
530
unsigned mask_offs = 0;
531
print_vec_selectors(fp, swizzle, mode, first_half, mask, &mask_offs);
532
if (mode == midgard_reg_mode_8 || mode == midgard_reg_mode_16)
533
print_vec_selectors(fp, swizzle, mode, second_half, mask, &mask_offs);
534
}
535
536
static void
537
print_scalar_constant(FILE *fp, unsigned src_binary,
538
const midgard_constants *consts,
539
midgard_scalar_alu *alu)
540
{
541
midgard_scalar_alu_src *src = (midgard_scalar_alu_src *)&src_binary;
542
assert(consts != NULL);
543
544
fprintf(fp, "#");
545
mir_print_constant_component(fp, consts, src->component,
546
src->full ?
547
midgard_reg_mode_32 : midgard_reg_mode_16,
548
false, src->mod, alu->op);
549
}
550
551
static void
552
print_vector_constants(FILE *fp, unsigned src_binary,
553
const midgard_constants *consts,
554
midgard_vector_alu *alu)
555
{
556
midgard_vector_alu_src *src = (midgard_vector_alu_src *)&src_binary;
557
bool expands = INPUT_EXPANDS(src->expand_mode);
558
unsigned bits = bits_for_mode_halved(alu->reg_mode, expands);
559
unsigned max_comp = (sizeof(*consts) * 8) / bits;
560
unsigned comp_mask, num_comp = 0;
561
562
assert(consts);
563
assert(max_comp <= 16);
564
565
comp_mask = effective_writemask(alu->op, condense_writemask(alu->mask, bits));
566
num_comp = util_bitcount(comp_mask);
567
568
fprintf(fp, "<");
569
bool first = true;
570
571
for (unsigned i = 0; i < max_comp; ++i) {
572
if (!(comp_mask & (1 << i))) continue;
573
574
unsigned c = (src->swizzle >> (i * 2)) & 3;
575
576
if (bits == 16 && !expands) {
577
bool upper = i >= 4;
578
579
switch (src->expand_mode) {
580
case midgard_src_passthrough:
581
c += upper * 4;
582
break;
583
case midgard_src_rep_low:
584
break;
585
case midgard_src_rep_high:
586
c += 4;
587
break;
588
case midgard_src_swap:
589
c += !upper * 4;
590
break;
591
default:
592
unreachable("invalid expand mode");
593
break;
594
}
595
} else if (bits == 32 && !expands) {
596
/* Implicitly ok */
597
} else if (bits == 64 && !expands) {
598
/* Implicitly ok */
599
} else if (bits == 8 && !expands) {
600
bool upper = i >= 8;
601
602
unsigned index = (i >> 1) & 3;
603
unsigned base = (src->swizzle >> (index * 2)) & 3;
604
c = base * 2;
605
606
switch (src->expand_mode) {
607
case midgard_src_passthrough:
608
c += upper * 8;
609
break;
610
case midgard_src_rep_low:
611
break;
612
case midgard_src_rep_high:
613
c += 8;
614
break;
615
case midgard_src_swap:
616
c += !upper * 8;
617
break;
618
default:
619
unreachable("invalid expand mode");
620
break;
621
}
622
623
/* We work on twos, actually */
624
if (i & 1)
625
c++;
626
} else {
627
printf(" (%u)", src->expand_mode);
628
}
629
630
if (first)
631
first = false;
632
else
633
fprintf(fp, ", ");
634
635
mir_print_constant_component(fp, consts, c, alu->reg_mode,
636
expands, src->mod, alu->op);
637
}
638
639
if (num_comp > 1)
640
fprintf(fp, ">");
641
}
642
643
static void
644
print_srcmod(FILE *fp, bool is_int, bool expands, unsigned mod, bool scalar)
645
{
646
/* Modifiers change meaning depending on the op's context */
647
648
if (is_int) {
649
if (expands)
650
fprintf(fp, "%s", srcmod_names_int[mod]);
651
} else {
652
if (mod & MIDGARD_FLOAT_MOD_ABS)
653
fprintf(fp, ".abs");
654
if (mod & MIDGARD_FLOAT_MOD_NEG)
655
fprintf(fp, ".neg");
656
if (expands)
657
fprintf(fp, ".widen");
658
}
659
}
660
661
static void
662
print_vector_src(FILE *fp, unsigned src_binary,
663
midgard_reg_mode mode, unsigned reg,
664
midgard_shrink_mode shrink_mode,
665
uint8_t src_mask, bool is_int,
666
midgard_special_arg_mod arg_mod)
667
{
668
midgard_vector_alu_src *src = (midgard_vector_alu_src *)&src_binary;
669
670
validate_expand_mode(src->expand_mode, mode);
671
672
print_alu_reg(fp, reg, false);
673
674
print_vec_swizzle(fp, src->swizzle, src->expand_mode, mode, src_mask);
675
676
fprintf(fp, "%s", argmod_names[arg_mod]);
677
678
print_srcmod(fp, is_int, INPUT_EXPANDS(src->expand_mode), src->mod, false);
679
}
680
681
static uint16_t
682
decode_vector_imm(unsigned src2_reg, unsigned imm)
683
{
684
uint16_t ret;
685
ret = src2_reg << 11;
686
ret |= (imm & 0x7) << 8;
687
ret |= (imm >> 3) & 0xFF;
688
return ret;
689
}
690
691
static void
692
print_immediate(FILE *fp, uint16_t imm)
693
{
694
if (is_instruction_int)
695
fprintf(fp, "#%u", imm);
696
else
697
fprintf(fp, "#%g", _mesa_half_to_float(imm));
698
}
699
700
static void
701
update_dest(unsigned reg)
702
{
703
/* We should record writes as marking this as a work register. Store
704
* the max register in work_count; we'll add one at the end */
705
706
if (reg < 16) {
707
midg_stats.work_count = MAX2(reg, midg_stats.work_count);
708
midg_ever_written |= (1 << reg);
709
}
710
}
711
712
static void
713
print_dest(FILE *fp, unsigned reg)
714
{
715
update_dest(reg);
716
print_alu_reg(fp, reg, true);
717
}
718
719
/* For 16-bit+ masks, we read off from the 8-bit mask field. For 16-bit (vec8),
720
* it's just one bit per channel, easy peasy. For 32-bit (vec4), it's one bit
721
* per channel with one duplicate bit in the middle. For 64-bit (vec2), it's
722
* one-bit per channel with _3_ duplicate bits in the middle. Basically, just
723
* subdividing the 128-bit word in 16-bit increments. For 64-bit, we uppercase
724
* the mask to make it obvious what happened */
725
726
static void
727
print_alu_mask(FILE *fp, uint8_t mask, unsigned bits, midgard_shrink_mode shrink_mode)
728
{
729
/* Skip 'complete' masks */
730
731
if (shrink_mode == midgard_shrink_mode_none && mask == 0xFF)
732
return;
733
734
fprintf(fp, ".");
735
736
unsigned skip = MAX2(bits / 16, 1);
737
bool uppercase = bits > 32;
738
bool tripped = false;
739
740
/* To apply an upper destination shrink_mode, we "shift" the alphabet.
741
* E.g. with an upper shrink_mode on 32-bit, instead of xyzw, print efgh.
742
* For upper 16-bit, instead of xyzwefgh, print ijklmnop */
743
744
const char *alphabet = components;
745
746
if (shrink_mode == midgard_shrink_mode_upper) {
747
assert(bits != 8);
748
alphabet += (128 / bits);
749
}
750
751
for (unsigned i = 0; i < 8; i += skip) {
752
bool a = (mask & (1 << i)) != 0;
753
754
for (unsigned j = 1; j < skip; ++j) {
755
bool dupe = (mask & (1 << (i + j))) != 0;
756
tripped |= (dupe != a);
757
}
758
759
if (a) {
760
/* TODO: handle shrinking from 16-bit */
761
unsigned comp_idx = bits == 8 ? i * 2 : i;
762
char c = alphabet[comp_idx / skip];
763
764
if (uppercase) {
765
c = toupper(c);
766
assert(c == 'X' || c == 'Y');
767
}
768
769
fprintf(fp, "%c", c);
770
if (bits == 8)
771
fprintf(fp, "%c", alphabet[comp_idx+1]);
772
}
773
}
774
775
if (tripped)
776
fprintf(fp, " /* %X */", mask);
777
}
778
779
/* TODO: 16-bit mode */
780
static void
781
print_ldst_mask(FILE *fp, unsigned mask, unsigned swizzle) {
782
fprintf(fp, ".");
783
784
for (unsigned i = 0; i < 4; ++i) {
785
bool write = (mask & (1 << i)) != 0;
786
unsigned c = (swizzle >> (i * 2)) & 3;
787
/* We can't omit the swizzle here since many ldst ops have a
788
* combined swizzle/writemask, and it would be ambiguous to not
789
* print the masked-out components. */
790
fprintf(fp, "%c", write ? components[c] : '~');
791
}
792
}
793
794
static void
795
print_tex_mask(FILE *fp, unsigned mask, bool upper)
796
{
797
if (mask == 0xF) {
798
if (upper)
799
fprintf(fp, "'");
800
801
return;
802
}
803
804
fprintf(fp, ".");
805
806
for (unsigned i = 0; i < 4; ++i) {
807
bool a = (mask & (1 << i)) != 0;
808
if (a)
809
fprintf(fp, "%c", components[i + (upper ? 4 : 0)]);
810
}
811
}
812
813
static void
814
print_vector_field(FILE *fp, const char *name, uint16_t *words, uint16_t reg_word,
815
const midgard_constants *consts, unsigned tabs, bool verbose)
816
{
817
midgard_reg_info *reg_info = (midgard_reg_info *)&reg_word;
818
midgard_vector_alu *alu_field = (midgard_vector_alu *) words;
819
midgard_reg_mode mode = alu_field->reg_mode;
820
midgard_alu_op op = alu_field->op;
821
unsigned shrink_mode = alu_field->shrink_mode;
822
bool is_int = midgard_is_integer_op(op);
823
bool is_int_out = midgard_is_integer_out_op(op);
824
825
if (verbose)
826
fprintf(fp, "%s.", name);
827
828
print_alu_opcode(fp, alu_field->op);
829
830
/* Print lane width */
831
fprintf(fp, ".%c%d", is_int_out ? 'i' : 'f', bits_for_mode(mode));
832
833
fprintf(fp, " ");
834
835
/* Mask denoting status of 8-lanes */
836
uint8_t mask = alu_field->mask;
837
838
/* First, print the destination */
839
print_dest(fp, reg_info->out_reg);
840
841
if (shrink_mode != midgard_shrink_mode_none) {
842
bool shrinkable = (mode != midgard_reg_mode_8);
843
bool known = shrink_mode != 0x3; /* Unused value */
844
845
if (!(shrinkable && known))
846
fprintf(fp, "/* do%u */ ", shrink_mode);
847
}
848
849
/* Instructions like fdot4 do *not* replicate, ensure the
850
* mask is of only a single component */
851
852
unsigned rep = GET_CHANNEL_COUNT(alu_opcode_props[op].props);
853
854
if (rep) {
855
unsigned comp_mask = condense_writemask(mask, bits_for_mode(mode));
856
unsigned num_comp = util_bitcount(comp_mask);
857
if (num_comp != 1)
858
fprintf(fp, "/* err too many components */");
859
}
860
print_alu_mask(fp, mask, bits_for_mode(mode), shrink_mode);
861
862
/* Print output modifiers */
863
864
print_alu_outmod(fp, alu_field->outmod, is_int_out, shrink_mode != midgard_shrink_mode_none);
865
866
/* Mask out unused components based on the writemask, but don't mask out
867
* components that are used for interlane instructions like fdot3. */
868
uint8_t src_mask =
869
rep ? expand_writemask(mask_of(rep), log2(128 / bits_for_mode(mode))) : mask;
870
871
fprintf(fp, ", ");
872
873
if (reg_info->src1_reg == REGISTER_CONSTANT)
874
print_vector_constants(fp, alu_field->src1, consts, alu_field);
875
else {
876
midgard_special_arg_mod argmod = midgard_alu_special_arg_mod(op, 1);
877
print_vector_src(fp, alu_field->src1, mode, reg_info->src1_reg,
878
shrink_mode, src_mask, is_int, argmod);
879
}
880
881
fprintf(fp, ", ");
882
883
if (reg_info->src2_imm) {
884
uint16_t imm = decode_vector_imm(reg_info->src2_reg, alu_field->src2 >> 2);
885
print_immediate(fp, imm);
886
} else if (reg_info->src2_reg == REGISTER_CONSTANT) {
887
print_vector_constants(fp, alu_field->src2, consts, alu_field);
888
} else {
889
midgard_special_arg_mod argmod = midgard_alu_special_arg_mod(op, 2);
890
print_vector_src(fp, alu_field->src2, mode, reg_info->src2_reg,
891
shrink_mode, src_mask, is_int, argmod);
892
}
893
894
midg_stats.instruction_count++;
895
fprintf(fp, "\n");
896
}
897
898
static void
899
print_scalar_src(FILE *fp, bool is_int, unsigned src_binary, unsigned reg)
900
{
901
midgard_scalar_alu_src *src = (midgard_scalar_alu_src *)&src_binary;
902
903
print_alu_reg(fp, reg, false);
904
905
unsigned c = src->component;
906
907
if (src->full) {
908
assert((c & 1) == 0);
909
c >>= 1;
910
}
911
912
fprintf(fp, ".%c", components[c]);
913
914
print_srcmod(fp, is_int, !src->full, src->mod, true);
915
}
916
917
static uint16_t
918
decode_scalar_imm(unsigned src2_reg, unsigned imm)
919
{
920
uint16_t ret;
921
ret = src2_reg << 11;
922
ret |= (imm & 3) << 9;
923
ret |= (imm & 4) << 6;
924
ret |= (imm & 0x38) << 2;
925
ret |= imm >> 6;
926
return ret;
927
}
928
929
static void
930
print_scalar_field(FILE *fp, const char *name, uint16_t *words, uint16_t reg_word,
931
const midgard_constants *consts, unsigned tabs, bool verbose)
932
{
933
midgard_reg_info *reg_info = (midgard_reg_info *)&reg_word;
934
midgard_scalar_alu *alu_field = (midgard_scalar_alu *) words;
935
bool is_int = midgard_is_integer_op(alu_field->op);
936
bool is_int_out = midgard_is_integer_out_op(alu_field->op);
937
bool full = alu_field->output_full;
938
939
if (alu_field->unknown)
940
fprintf(fp, "scalar ALU unknown bit set\n");
941
942
if (verbose)
943
fprintf(fp, "%s.", name);
944
945
print_alu_opcode(fp, alu_field->op);
946
947
/* Print lane width, in this case the lane width is always 32-bit, but
948
* we print it anyway to make it consistent with the other instructions. */
949
fprintf(fp, ".%c32", is_int_out ? 'i' : 'f');
950
951
fprintf(fp, " ");
952
953
print_dest(fp, reg_info->out_reg);
954
unsigned c = alu_field->output_component;
955
956
if (full) {
957
assert((c & 1) == 0);
958
c >>= 1;
959
}
960
961
fprintf(fp, ".%c", components[c]);
962
963
print_alu_outmod(fp, alu_field->outmod, is_int_out, !full);
964
965
fprintf(fp, ", ");
966
967
if (reg_info->src1_reg == REGISTER_CONSTANT)
968
print_scalar_constant(fp, alu_field->src1, consts, alu_field);
969
else
970
print_scalar_src(fp, is_int, alu_field->src1, reg_info->src1_reg);
971
972
fprintf(fp, ", ");
973
974
if (reg_info->src2_imm) {
975
uint16_t imm = decode_scalar_imm(reg_info->src2_reg,
976
alu_field->src2);
977
print_immediate(fp, imm);
978
} else if (reg_info->src2_reg == REGISTER_CONSTANT) {
979
print_scalar_constant(fp, alu_field->src2, consts, alu_field);
980
} else
981
print_scalar_src(fp, is_int, alu_field->src2, reg_info->src2_reg);
982
983
midg_stats.instruction_count++;
984
fprintf(fp, "\n");
985
}
986
987
static void
988
print_branch_op(FILE *fp, unsigned op)
989
{
990
switch (op) {
991
case midgard_jmp_writeout_op_branch_uncond:
992
fprintf(fp, "uncond.");
993
break;
994
995
case midgard_jmp_writeout_op_branch_cond:
996
fprintf(fp, "cond.");
997
break;
998
999
case midgard_jmp_writeout_op_writeout:
1000
fprintf(fp, "write.");
1001
break;
1002
1003
case midgard_jmp_writeout_op_tilebuffer_pending:
1004
fprintf(fp, "tilebuffer.");
1005
break;
1006
1007
case midgard_jmp_writeout_op_discard:
1008
fprintf(fp, "discard.");
1009
break;
1010
1011
default:
1012
fprintf(fp, "unk%u.", op);
1013
break;
1014
}
1015
}
1016
1017
static void
1018
print_branch_cond(FILE *fp, int cond)
1019
{
1020
switch (cond) {
1021
case midgard_condition_write0:
1022
fprintf(fp, "write0");
1023
break;
1024
1025
case midgard_condition_false:
1026
fprintf(fp, "false");
1027
break;
1028
1029
case midgard_condition_true:
1030
fprintf(fp, "true");
1031
break;
1032
1033
case midgard_condition_always:
1034
fprintf(fp, "always");
1035
break;
1036
1037
default:
1038
fprintf(fp, "unk%X", cond);
1039
break;
1040
}
1041
}
1042
1043
static bool
1044
print_compact_branch_writeout_field(FILE *fp, uint16_t word)
1045
{
1046
midgard_jmp_writeout_op op = word & 0x7;
1047
midg_stats.instruction_count++;
1048
1049
switch (op) {
1050
case midgard_jmp_writeout_op_branch_uncond: {
1051
midgard_branch_uncond br_uncond;
1052
memcpy((char *) &br_uncond, (char *) &word, sizeof(br_uncond));
1053
fprintf(fp, "br.uncond ");
1054
1055
if (br_uncond.unknown != 1)
1056
fprintf(fp, "unknown:%u, ", br_uncond.unknown);
1057
1058
if (br_uncond.offset >= 0)
1059
fprintf(fp, "+");
1060
1061
fprintf(fp, "%d -> %s", br_uncond.offset,
1062
midgard_tag_props[br_uncond.dest_tag].name);
1063
fprintf(fp, "\n");
1064
1065
return br_uncond.offset >= 0;
1066
}
1067
1068
case midgard_jmp_writeout_op_branch_cond:
1069
case midgard_jmp_writeout_op_writeout:
1070
case midgard_jmp_writeout_op_discard:
1071
default: {
1072
midgard_branch_cond br_cond;
1073
memcpy((char *) &br_cond, (char *) &word, sizeof(br_cond));
1074
1075
fprintf(fp, "br.");
1076
1077
print_branch_op(fp, br_cond.op);
1078
print_branch_cond(fp, br_cond.cond);
1079
1080
fprintf(fp, " ");
1081
1082
if (br_cond.offset >= 0)
1083
fprintf(fp, "+");
1084
1085
fprintf(fp, "%d -> %s", br_cond.offset,
1086
midgard_tag_props[br_cond.dest_tag].name);
1087
fprintf(fp, "\n");
1088
1089
return br_cond.offset >= 0;
1090
}
1091
}
1092
1093
return false;
1094
}
1095
1096
static bool
1097
print_extended_branch_writeout_field(FILE *fp, uint8_t *words, unsigned next)
1098
{
1099
midgard_branch_extended br;
1100
memcpy((char *) &br, (char *) words, sizeof(br));
1101
1102
fprintf(fp, "brx.");
1103
1104
print_branch_op(fp, br.op);
1105
1106
/* Condition codes are a LUT in the general case, but simply repeated 8 times for single-channel conditions.. Check this. */
1107
1108
bool single_channel = true;
1109
1110
for (unsigned i = 0; i < 16; i += 2) {
1111
single_channel &= (((br.cond >> i) & 0x3) == (br.cond & 0x3));
1112
}
1113
1114
if (single_channel)
1115
print_branch_cond(fp, br.cond & 0x3);
1116
else
1117
fprintf(fp, "lut%X", br.cond);
1118
1119
if (br.unknown)
1120
fprintf(fp, ".unknown%u", br.unknown);
1121
1122
fprintf(fp, " ");
1123
1124
if (br.offset >= 0)
1125
fprintf(fp, "+");
1126
1127
fprintf(fp, "%d -> %s\n", br.offset,
1128
midgard_tag_props[br.dest_tag].name);
1129
1130
unsigned I = next + br.offset * 4;
1131
1132
if (midg_tags[I] && midg_tags[I] != br.dest_tag) {
1133
fprintf(fp, "\t/* XXX TAG ERROR: jumping to %s but tagged %s \n",
1134
midgard_tag_props[br.dest_tag].name,
1135
midgard_tag_props[midg_tags[I]].name);
1136
}
1137
1138
midg_tags[I] = br.dest_tag;
1139
1140
midg_stats.instruction_count++;
1141
return br.offset >= 0;
1142
}
1143
1144
static unsigned
1145
num_alu_fields_enabled(uint32_t control_word)
1146
{
1147
unsigned ret = 0;
1148
1149
if ((control_word >> 17) & 1)
1150
ret++;
1151
1152
if ((control_word >> 19) & 1)
1153
ret++;
1154
1155
if ((control_word >> 21) & 1)
1156
ret++;
1157
1158
if ((control_word >> 23) & 1)
1159
ret++;
1160
1161
if ((control_word >> 25) & 1)
1162
ret++;
1163
1164
return ret;
1165
}
1166
1167
static bool
1168
print_alu_word(FILE *fp, uint32_t *words, unsigned num_quad_words,
1169
unsigned tabs, unsigned next, bool verbose)
1170
{
1171
uint32_t control_word = words[0];
1172
uint16_t *beginning_ptr = (uint16_t *)(words + 1);
1173
unsigned num_fields = num_alu_fields_enabled(control_word);
1174
uint16_t *word_ptr = beginning_ptr + num_fields;
1175
unsigned num_words = 2 + num_fields;
1176
const midgard_constants *consts = NULL;
1177
bool branch_forward = false;
1178
1179
if ((control_word >> 17) & 1)
1180
num_words += 3;
1181
1182
if ((control_word >> 19) & 1)
1183
num_words += 2;
1184
1185
if ((control_word >> 21) & 1)
1186
num_words += 3;
1187
1188
if ((control_word >> 23) & 1)
1189
num_words += 2;
1190
1191
if ((control_word >> 25) & 1)
1192
num_words += 3;
1193
1194
if ((control_word >> 26) & 1)
1195
num_words += 1;
1196
1197
if ((control_word >> 27) & 1)
1198
num_words += 3;
1199
1200
if (num_quad_words > (num_words + 7) / 8) {
1201
assert(num_quad_words == (num_words + 15) / 8);
1202
//Assume that the extra quadword is constants
1203
consts = (midgard_constants *)(words + (4 * num_quad_words - 4));
1204
}
1205
1206
if ((control_word >> 16) & 1)
1207
fprintf(fp, "unknown bit 16 enabled\n");
1208
1209
if ((control_word >> 17) & 1) {
1210
print_vector_field(fp, "vmul", word_ptr, *beginning_ptr, consts, tabs, verbose);
1211
beginning_ptr += 1;
1212
word_ptr += 3;
1213
}
1214
1215
if ((control_word >> 18) & 1)
1216
fprintf(fp, "unknown bit 18 enabled\n");
1217
1218
if ((control_word >> 19) & 1) {
1219
print_scalar_field(fp, "sadd", word_ptr, *beginning_ptr, consts, tabs, verbose);
1220
beginning_ptr += 1;
1221
word_ptr += 2;
1222
}
1223
1224
if ((control_word >> 20) & 1)
1225
fprintf(fp, "unknown bit 20 enabled\n");
1226
1227
if ((control_word >> 21) & 1) {
1228
print_vector_field(fp, "vadd", word_ptr, *beginning_ptr, consts, tabs, verbose);
1229
beginning_ptr += 1;
1230
word_ptr += 3;
1231
}
1232
1233
if ((control_word >> 22) & 1)
1234
fprintf(fp, "unknown bit 22 enabled\n");
1235
1236
if ((control_word >> 23) & 1) {
1237
print_scalar_field(fp, "smul", word_ptr, *beginning_ptr, consts, tabs, verbose);
1238
beginning_ptr += 1;
1239
word_ptr += 2;
1240
}
1241
1242
if ((control_word >> 24) & 1)
1243
fprintf(fp, "unknown bit 24 enabled\n");
1244
1245
if ((control_word >> 25) & 1) {
1246
print_vector_field(fp, "lut", word_ptr, *beginning_ptr, consts, tabs, verbose);
1247
word_ptr += 3;
1248
}
1249
1250
if ((control_word >> 26) & 1) {
1251
branch_forward |= print_compact_branch_writeout_field(fp, *word_ptr);
1252
word_ptr += 1;
1253
}
1254
1255
if ((control_word >> 27) & 1) {
1256
branch_forward |= print_extended_branch_writeout_field(fp, (uint8_t *) word_ptr, next);
1257
word_ptr += 3;
1258
}
1259
1260
if (consts)
1261
fprintf(fp, "uconstants 0x%X, 0x%X, 0x%X, 0x%X\n",
1262
consts->u32[0], consts->u32[1],
1263
consts->u32[2], consts->u32[3]);
1264
1265
return branch_forward;
1266
}
1267
1268
/* TODO: how can we use this now that we know that these params can't be known
1269
* before run time in every single case? Maybe just use it in the cases we can? */
1270
UNUSED static void
1271
print_varying_parameters(FILE *fp, midgard_load_store_word *word)
1272
{
1273
midgard_varying_params p = midgard_unpack_varying_params(*word);
1274
1275
/* If a varying, there are qualifiers */
1276
if (p.flat_shading)
1277
fprintf(fp, ".flat");
1278
1279
if (p.perspective_correction)
1280
fprintf(fp, ".correction");
1281
1282
if (p.centroid_mapping)
1283
fprintf(fp, ".centroid");
1284
1285
if (p.interpolate_sample)
1286
fprintf(fp, ".sample");
1287
1288
switch (p.modifier) {
1289
case midgard_varying_mod_perspective_y:
1290
fprintf(fp, ".perspectivey");
1291
break;
1292
case midgard_varying_mod_perspective_z:
1293
fprintf(fp, ".perspectivez");
1294
break;
1295
case midgard_varying_mod_perspective_w:
1296
fprintf(fp, ".perspectivew");
1297
break;
1298
default:
1299
unreachable("invalid varying modifier");
1300
break;
1301
}
1302
}
1303
1304
static bool
1305
is_op_varying(unsigned op)
1306
{
1307
switch (op) {
1308
case midgard_op_st_vary_16:
1309
case midgard_op_st_vary_32:
1310
case midgard_op_st_vary_32i:
1311
case midgard_op_st_vary_32u:
1312
case midgard_op_ld_vary_16:
1313
case midgard_op_ld_vary_32:
1314
case midgard_op_ld_vary_32i:
1315
case midgard_op_ld_vary_32u:
1316
return true;
1317
}
1318
1319
return false;
1320
}
1321
1322
static bool
1323
is_op_attribute(unsigned op)
1324
{
1325
switch (op) {
1326
case midgard_op_ld_attr_16:
1327
case midgard_op_ld_attr_32:
1328
case midgard_op_ld_attr_32i:
1329
case midgard_op_ld_attr_32u:
1330
return true;
1331
}
1332
1333
return false;
1334
}
1335
1336
/* Helper to print integer well-formatted, but only when non-zero. */
1337
static void
1338
midgard_print_sint(FILE *fp, int n)
1339
{
1340
if (n > 0)
1341
fprintf(fp, " + 0x%X", n);
1342
else if (n < 0)
1343
fprintf(fp, " - 0x%X", -n);
1344
}
1345
1346
static void
1347
update_stats(signed *stat, unsigned address)
1348
{
1349
if (*stat >= 0)
1350
*stat = MAX2(*stat, address + 1);
1351
}
1352
1353
static void
1354
print_load_store_instr(FILE *fp, uint64_t data, bool verbose)
1355
{
1356
midgard_load_store_word *word = (midgard_load_store_word *) &data;
1357
1358
print_ld_st_opcode(fp, word->op);
1359
1360
if (word->op == midgard_op_trap) {
1361
fprintf(fp, " 0x%X\n", word->signed_offset);
1362
return;
1363
}
1364
1365
/* Print opcode modifiers */
1366
1367
if (OP_USES_ATTRIB(word->op)) {
1368
/* Print non-default attribute tables */
1369
bool default_secondary =
1370
(word->op == midgard_op_st_vary_32) ||
1371
(word->op == midgard_op_st_vary_16) ||
1372
(word->op == midgard_op_st_vary_32u) ||
1373
(word->op == midgard_op_st_vary_32i) ||
1374
(word->op == midgard_op_ld_vary_32) ||
1375
(word->op == midgard_op_ld_vary_16) ||
1376
(word->op == midgard_op_ld_vary_32u) ||
1377
(word->op == midgard_op_ld_vary_32i);
1378
1379
bool default_primary =
1380
(word->op == midgard_op_ld_attr_32) ||
1381
(word->op == midgard_op_ld_attr_16) ||
1382
(word->op == midgard_op_ld_attr_32u) ||
1383
(word->op == midgard_op_ld_attr_32i);
1384
1385
bool has_default = (default_secondary || default_primary);
1386
bool is_secondary = (word->index_format >> 1);
1387
1388
if (has_default && (is_secondary != default_secondary))
1389
fprintf(fp, ".%s", is_secondary ? "secondary" : "primary");
1390
} else if (word->op == midgard_op_ld_cubemap_coords || OP_IS_PROJECTION(word->op))
1391
fprintf(fp, ".%s", word->bitsize_toggle ? "f32" : "f16");
1392
1393
fprintf(fp, " ");
1394
1395
/* src/dest register */
1396
1397
if (!OP_IS_STORE(word->op)) {
1398
print_ldst_write_reg(fp, word->reg);
1399
1400
/* Some opcodes don't have a swizzable src register, and
1401
* instead the swizzle is applied before the result is written
1402
* to the dest reg. For these ops, we combine the writemask
1403
* with the swizzle to display them in the disasm compactly. */
1404
unsigned swizzle = word->swizzle;
1405
if ((OP_IS_REG2REG_LDST(word->op) &&
1406
word->op != midgard_op_lea &&
1407
word->op != midgard_op_lea_image) || OP_IS_ATOMIC(word->op))
1408
swizzle = 0xE4;
1409
print_ldst_mask(fp, word->mask, swizzle);
1410
} else {
1411
print_ldst_read_reg(fp, word->reg);
1412
print_vec_swizzle(fp, word->swizzle, midgard_src_passthrough,
1413
midgard_reg_mode_32, 0xFF);
1414
}
1415
1416
/* ld_ubo args */
1417
if (OP_IS_UBO_READ(word->op)) {
1418
if (word->signed_offset & 1) { /* buffer index imm */
1419
unsigned imm = midgard_unpack_ubo_index_imm(*word);
1420
fprintf(fp, ", %u", imm);
1421
} else { /* buffer index from reg */
1422
fprintf(fp, ", ");
1423
print_ldst_read_reg(fp, word->arg_reg);
1424
fprintf(fp, ".%c", components[word->arg_comp]);
1425
}
1426
1427
fprintf(fp, ", ");
1428
print_ldst_read_reg(fp, word->index_reg);
1429
fprintf(fp, ".%c", components[word->index_comp]);
1430
if (word->index_shift)
1431
fprintf(fp, " lsl %u", word->index_shift);
1432
midgard_print_sint(fp, UNPACK_LDST_UBO_OFS(word->signed_offset));
1433
}
1434
1435
/* mem addr expression */
1436
if (OP_HAS_ADDRESS(word->op)) {
1437
fprintf(fp, ", ");
1438
bool first = true;
1439
1440
/* Skip printing zero */
1441
if (word->arg_reg != 7 || verbose) {
1442
print_ldst_read_reg(fp, word->arg_reg);
1443
fprintf(fp, ".u%d.%c",
1444
word->bitsize_toggle ? 64 : 32, components[word->arg_comp]);
1445
first = false;
1446
}
1447
1448
if ((word->op < midgard_op_atomic_cmpxchg ||
1449
word->op > midgard_op_atomic_cmpxchg64_be) &&
1450
word->index_reg != 0x7) {
1451
if (!first)
1452
fprintf(fp, " + ");
1453
1454
print_ldst_read_reg(fp, word->index_reg);
1455
fprintf(fp, "%s.%c",
1456
index_format_names[word->index_format],
1457
components[word->index_comp]);
1458
if (word->index_shift)
1459
fprintf(fp, " lsl %u", word->index_shift);
1460
}
1461
1462
midgard_print_sint(fp, word->signed_offset);
1463
}
1464
1465
/* src reg for reg2reg ldst opcodes */
1466
if (OP_IS_REG2REG_LDST(word->op)) {
1467
fprintf(fp, ", ");
1468
print_ldst_read_reg(fp, word->arg_reg);
1469
print_vec_swizzle(fp, word->swizzle, midgard_src_passthrough,
1470
midgard_reg_mode_32, 0xFF);
1471
}
1472
1473
/* atomic ops encode the source arg where the ldst swizzle would be. */
1474
if (OP_IS_ATOMIC(word->op)) {
1475
unsigned src = (word->swizzle >> 2) & 0x7;
1476
unsigned src_comp = word->swizzle & 0x3;
1477
fprintf(fp, ", ");
1478
print_ldst_read_reg(fp, src);
1479
fprintf(fp, ".%c", components[src_comp]);
1480
}
1481
1482
/* CMPXCHG encodes the extra comparison arg where the index reg would be. */
1483
if (word->op >= midgard_op_atomic_cmpxchg &&
1484
word->op <= midgard_op_atomic_cmpxchg64_be) {
1485
fprintf(fp, ", ");
1486
print_ldst_read_reg(fp, word->index_reg);
1487
fprintf(fp, ".%c", components[word->index_comp]);
1488
}
1489
1490
/* index reg for attr/vary/images, selector for ld/st_special */
1491
if (OP_IS_SPECIAL(word->op) || OP_USES_ATTRIB(word->op)) {
1492
fprintf(fp, ", ");
1493
print_ldst_read_reg(fp, word->index_reg);
1494
fprintf(fp, ".%c", components[word->index_comp]);
1495
if (word->index_shift)
1496
fprintf(fp, " lsl %u", word->index_shift);
1497
midgard_print_sint(fp, UNPACK_LDST_ATTRIB_OFS(word->signed_offset));
1498
}
1499
1500
/* vertex reg for attrib/varying ops, coord reg for image ops */
1501
if (OP_USES_ATTRIB(word->op)) {
1502
fprintf(fp, ", ");
1503
print_ldst_read_reg(fp, word->arg_reg);
1504
1505
if (OP_IS_IMAGE(word->op))
1506
fprintf(fp, ".u%d", word->bitsize_toggle ? 64 : 32);
1507
1508
fprintf(fp, ".%c", components[word->arg_comp]);
1509
1510
if (word->bitsize_toggle && !OP_IS_IMAGE(word->op))
1511
midgard_print_sint(fp, UNPACK_LDST_VERTEX_OFS(word->signed_offset));
1512
}
1513
1514
/* TODO: properly decode format specifier for PACK/UNPACK ops */
1515
if (OP_IS_PACK_COLOUR(word->op) || OP_IS_UNPACK_COLOUR(word->op)) {
1516
fprintf(fp, ", ");
1517
unsigned format_specifier = (word->signed_offset << 4) | word->index_shift;
1518
fprintf(fp, "0x%X", format_specifier);
1519
}
1520
1521
fprintf(fp, "\n");
1522
1523
/* Debugging stuff */
1524
1525
if (is_op_varying(word->op)) {
1526
/* Do some analysis: check if direct access */
1527
1528
if (word->index_reg == 0x7 && midg_stats.varying_count >= 0)
1529
update_stats(&midg_stats.varying_count,
1530
UNPACK_LDST_ATTRIB_OFS(word->signed_offset));
1531
else
1532
midg_stats.varying_count = -16;
1533
} else if (is_op_attribute(word->op)) {
1534
if (word->index_reg == 0x7 && midg_stats.attribute_count >= 0)
1535
update_stats(&midg_stats.attribute_count,
1536
UNPACK_LDST_ATTRIB_OFS(word->signed_offset));
1537
else
1538
midg_stats.attribute_count = -16;
1539
}
1540
1541
if (!OP_IS_STORE(word->op))
1542
update_dest(word->reg);
1543
1544
if (OP_IS_UBO_READ(word->op))
1545
update_stats(&midg_stats.uniform_buffer_count,
1546
UNPACK_LDST_UBO_OFS(word->signed_offset));
1547
1548
midg_stats.instruction_count++;
1549
}
1550
1551
static void
1552
print_load_store_word(FILE *fp, uint32_t *word, bool verbose)
1553
{
1554
midgard_load_store *load_store = (midgard_load_store *) word;
1555
1556
if (load_store->word1 != 3) {
1557
print_load_store_instr(fp, load_store->word1, verbose);
1558
}
1559
1560
if (load_store->word2 != 3) {
1561
print_load_store_instr(fp, load_store->word2, verbose);
1562
}
1563
}
1564
1565
static void
1566
print_texture_reg_select(FILE *fp, uint8_t u, unsigned base)
1567
{
1568
midgard_tex_register_select sel;
1569
memcpy(&sel, &u, sizeof(u));
1570
1571
print_tex_reg(fp, base + sel.select, false);
1572
1573
unsigned component = sel.component;
1574
1575
/* Use the upper half in half-reg mode */
1576
if (sel.upper) {
1577
assert(!sel.full);
1578
component += 4;
1579
}
1580
1581
fprintf(fp, ".%c.%d", components[component], sel.full ? 32 : 16);
1582
1583
assert(sel.zero == 0);
1584
}
1585
1586
static void
1587
print_texture_format(FILE *fp, int format)
1588
{
1589
/* Act like a modifier */
1590
fprintf(fp, ".");
1591
1592
switch (format) {
1593
DEFINE_CASE(1, "1d");
1594
DEFINE_CASE(2, "2d");
1595
DEFINE_CASE(3, "3d");
1596
DEFINE_CASE(0, "cube");
1597
1598
default:
1599
unreachable("Bad format");
1600
}
1601
}
1602
1603
static bool
1604
midgard_op_has_helpers(unsigned op)
1605
{
1606
switch (op) {
1607
case midgard_tex_op_normal:
1608
case midgard_tex_op_derivative:
1609
return true;
1610
default:
1611
return false;
1612
}
1613
}
1614
1615
static void
1616
print_texture_op(FILE *fp, unsigned op)
1617
{
1618
if (tex_opcode_props[op].name)
1619
fprintf(fp, "%s", tex_opcode_props[op].name);
1620
else
1621
fprintf(fp, "tex_op_%02X", op);
1622
}
1623
1624
static bool
1625
texture_op_takes_bias(unsigned op)
1626
{
1627
return op == midgard_tex_op_normal;
1628
}
1629
1630
static char
1631
sampler_type_name(enum mali_sampler_type t)
1632
{
1633
switch (t) {
1634
case MALI_SAMPLER_FLOAT:
1635
return 'f';
1636
case MALI_SAMPLER_UNSIGNED:
1637
return 'u';
1638
case MALI_SAMPLER_SIGNED:
1639
return 'i';
1640
default:
1641
return '?';
1642
}
1643
1644
}
1645
1646
static void
1647
print_texture_barrier(FILE *fp, uint32_t *word)
1648
{
1649
midgard_texture_barrier_word *barrier = (midgard_texture_barrier_word *) word;
1650
1651
if (barrier->type != TAG_TEXTURE_4_BARRIER)
1652
fprintf(fp, "/* barrier tag %X != tex/bar */ ", barrier->type);
1653
1654
if (!barrier->cont)
1655
fprintf(fp, "/* cont missing? */");
1656
1657
if (!barrier->last)
1658
fprintf(fp, "/* last missing? */");
1659
1660
if (barrier->zero1)
1661
fprintf(fp, "/* zero1 = 0x%X */ ", barrier->zero1);
1662
1663
if (barrier->zero2)
1664
fprintf(fp, "/* zero2 = 0x%X */ ", barrier->zero2);
1665
1666
if (barrier->zero3)
1667
fprintf(fp, "/* zero3 = 0x%X */ ", barrier->zero3);
1668
1669
if (barrier->zero4)
1670
fprintf(fp, "/* zero4 = 0x%X */ ", barrier->zero4);
1671
1672
if (barrier->zero5)
1673
fprintf(fp, "/* zero4 = 0x%" PRIx64 " */ ", barrier->zero5);
1674
1675
if (barrier->out_of_order)
1676
fprintf(fp, ".ooo%u", barrier->out_of_order);
1677
1678
fprintf(fp, "\n");
1679
}
1680
1681
#undef DEFINE_CASE
1682
1683
static const char *
1684
texture_mode(enum mali_texture_mode mode)
1685
{
1686
switch (mode) {
1687
case TEXTURE_NORMAL: return "";
1688
case TEXTURE_SHADOW: return ".shadow";
1689
case TEXTURE_GATHER_SHADOW: return ".gather.shadow";
1690
case TEXTURE_GATHER_X: return ".gatherX";
1691
case TEXTURE_GATHER_Y: return ".gatherY";
1692
case TEXTURE_GATHER_Z: return ".gatherZ";
1693
case TEXTURE_GATHER_W: return ".gatherW";
1694
default: return "unk";
1695
}
1696
}
1697
1698
static const char *
1699
derivative_mode(enum mali_derivative_mode mode)
1700
{
1701
switch (mode) {
1702
case TEXTURE_DFDX: return ".x";
1703
case TEXTURE_DFDY: return ".y";
1704
default: return "unk";
1705
}
1706
}
1707
1708
static void
1709
print_texture_word(FILE *fp, uint32_t *word, unsigned tabs, unsigned in_reg_base, unsigned out_reg_base)
1710
{
1711
midgard_texture_word *texture = (midgard_texture_word *) word;
1712
midg_stats.helper_invocations |= midgard_op_has_helpers(texture->op);
1713
validate_sampler_type(texture->op, texture->sampler_type);
1714
1715
/* Broad category of texture operation in question */
1716
print_texture_op(fp, texture->op);
1717
1718
/* Barriers use a dramatically different code path */
1719
if (texture->op == midgard_tex_op_barrier) {
1720
print_texture_barrier(fp, word);
1721
return;
1722
} else if (texture->type == TAG_TEXTURE_4_BARRIER)
1723
fprintf (fp, "/* nonbarrier had tex/bar tag */ ");
1724
else if (texture->type == TAG_TEXTURE_4_VTX)
1725
fprintf (fp, ".vtx");
1726
1727
if (texture->op == midgard_tex_op_derivative)
1728
fprintf(fp, "%s", derivative_mode(texture->mode));
1729
else
1730
fprintf(fp, "%s", texture_mode(texture->mode));
1731
1732
/* Specific format in question */
1733
print_texture_format(fp, texture->format);
1734
1735
/* Instruction "modifiers" parallel the ALU instructions. */
1736
1737
if (texture->cont)
1738
fprintf(fp, ".cont");
1739
1740
if (texture->last)
1741
fprintf(fp, ".last");
1742
1743
if (texture->out_of_order)
1744
fprintf(fp, ".ooo%u", texture->out_of_order);
1745
1746
fprintf(fp, " ");
1747
print_tex_reg(fp, out_reg_base + texture->out_reg_select, true);
1748
print_tex_mask(fp, texture->mask, texture->out_upper);
1749
fprintf(fp, ".%c%d", texture->sampler_type == MALI_SAMPLER_FLOAT ? 'f' : 'i',
1750
texture->out_full ? 32 : 16);
1751
assert(!(texture->out_full && texture->out_upper));
1752
1753
/* Output modifiers are only valid for float texture operations */
1754
if (texture->sampler_type == MALI_SAMPLER_FLOAT)
1755
print_outmod(fp, texture->outmod, false);
1756
1757
fprintf(fp, ", ");
1758
1759
/* Depending on whether we read from textures directly or indirectly,
1760
* we may be able to update our analysis */
1761
1762
if (texture->texture_register) {
1763
fprintf(fp, "texture[");
1764
print_texture_reg_select(fp, texture->texture_handle, in_reg_base);
1765
fprintf(fp, "], ");
1766
1767
/* Indirect, tut tut */
1768
midg_stats.texture_count = -16;
1769
} else {
1770
fprintf(fp, "texture%u, ", texture->texture_handle);
1771
update_stats(&midg_stats.texture_count, texture->texture_handle);
1772
}
1773
1774
/* Print the type, GL style */
1775
fprintf(fp, "%csampler", sampler_type_name(texture->sampler_type));
1776
1777
if (texture->sampler_register) {
1778
fprintf(fp, "[");
1779
print_texture_reg_select(fp, texture->sampler_handle, in_reg_base);
1780
fprintf(fp, "]");
1781
1782
midg_stats.sampler_count = -16;
1783
} else {
1784
fprintf(fp, "%u", texture->sampler_handle);
1785
update_stats(&midg_stats.sampler_count, texture->sampler_handle);
1786
}
1787
1788
print_vec_swizzle(fp, texture->swizzle, midgard_src_passthrough, midgard_reg_mode_32, 0xFF);
1789
1790
fprintf(fp, ", ");
1791
1792
midgard_src_expand_mode exp =
1793
texture->in_reg_upper ? midgard_src_expand_high : midgard_src_passthrough;
1794
print_tex_reg(fp, in_reg_base + texture->in_reg_select, false);
1795
print_vec_swizzle(fp, texture->in_reg_swizzle, exp, midgard_reg_mode_32, 0xFF);
1796
fprintf(fp, ".%d", texture->in_reg_full ? 32 : 16);
1797
assert(!(texture->in_reg_full && texture->in_reg_upper));
1798
1799
/* There is *always* an offset attached. Of
1800
* course, that offset is just immediate #0 for a
1801
* GLES call that doesn't take an offset. If there
1802
* is a non-negative non-zero offset, this is
1803
* specified in immediate offset mode, with the
1804
* values in the offset_* fields as immediates. If
1805
* this is a negative offset, we instead switch to
1806
* a register offset mode, where the offset_*
1807
* fields become register triplets */
1808
1809
if (texture->offset_register) {
1810
fprintf(fp, " + ");
1811
1812
bool full = texture->offset & 1;
1813
bool select = texture->offset & 2;
1814
bool upper = texture->offset & 4;
1815
unsigned swizzle = texture->offset >> 3;
1816
midgard_src_expand_mode exp =
1817
upper ? midgard_src_expand_high : midgard_src_passthrough;
1818
1819
print_tex_reg(fp, in_reg_base + select, false);
1820
print_vec_swizzle(fp, swizzle, exp, midgard_reg_mode_32, 0xFF);
1821
fprintf(fp, ".%d", full ? 32 : 16);
1822
assert(!(texture->out_full && texture->out_upper));
1823
1824
fprintf(fp, ", ");
1825
} else if (texture->offset) {
1826
/* Only select ops allow negative immediate offsets, verify */
1827
1828
signed offset_x = (texture->offset & 0xF);
1829
signed offset_y = ((texture->offset >> 4) & 0xF);
1830
signed offset_z = ((texture->offset >> 8) & 0xF);
1831
1832
bool neg_x = offset_x < 0;
1833
bool neg_y = offset_y < 0;
1834
bool neg_z = offset_z < 0;
1835
bool any_neg = neg_x || neg_y || neg_z;
1836
1837
if (any_neg && texture->op != midgard_tex_op_fetch)
1838
fprintf(fp, "/* invalid negative */ ");
1839
1840
/* Regardless, just print the immediate offset */
1841
1842
fprintf(fp, " + <%d, %d, %d>, ", offset_x, offset_y, offset_z);
1843
} else {
1844
fprintf(fp, ", ");
1845
}
1846
1847
char lod_operand = texture_op_takes_bias(texture->op) ? '+' : '=';
1848
1849
if (texture->lod_register) {
1850
fprintf(fp, "lod %c ", lod_operand);
1851
print_texture_reg_select(fp, texture->bias, in_reg_base);
1852
fprintf(fp, ", ");
1853
1854
if (texture->bias_int)
1855
fprintf(fp, " /* bias_int = 0x%X */", texture->bias_int);
1856
} else if (texture->op == midgard_tex_op_fetch) {
1857
/* For texel fetch, the int LOD is in the fractional place and
1858
* there is no fraction. We *always* have an explicit LOD, even
1859
* if it's zero. */
1860
1861
if (texture->bias_int)
1862
fprintf(fp, " /* bias_int = 0x%X */ ", texture->bias_int);
1863
1864
fprintf(fp, "lod = %u, ", texture->bias);
1865
} else if (texture->bias || texture->bias_int) {
1866
signed bias_int = texture->bias_int;
1867
float bias_frac = texture->bias / 256.0f;
1868
float bias = bias_int + bias_frac;
1869
1870
bool is_bias = texture_op_takes_bias(texture->op);
1871
char sign = (bias >= 0.0) ? '+' : '-';
1872
char operand = is_bias ? sign : '=';
1873
1874
fprintf(fp, "lod %c %f, ", operand, fabsf(bias));
1875
}
1876
1877
fprintf(fp, "\n");
1878
1879
/* While not zero in general, for these simple instructions the
1880
* following unknowns are zero, so we don't include them */
1881
1882
if (texture->unknown4 ||
1883
texture->unknown8) {
1884
fprintf(fp, "// unknown4 = 0x%x\n", texture->unknown4);
1885
fprintf(fp, "// unknown8 = 0x%x\n", texture->unknown8);
1886
}
1887
1888
midg_stats.instruction_count++;
1889
}
1890
1891
struct midgard_disasm_stats
1892
disassemble_midgard(FILE *fp, uint8_t *code, size_t size, unsigned gpu_id, bool verbose)
1893
{
1894
uint32_t *words = (uint32_t *) code;
1895
unsigned num_words = size / 4;
1896
int tabs = 0;
1897
1898
bool branch_forward = false;
1899
1900
int last_next_tag = -1;
1901
1902
unsigned i = 0;
1903
1904
midg_tags = calloc(sizeof(midg_tags[0]), num_words);
1905
1906
/* Stats for shader-db */
1907
memset(&midg_stats, 0, sizeof(midg_stats));
1908
midg_ever_written = 0;
1909
1910
while (i < num_words) {
1911
unsigned tag = words[i] & 0xF;
1912
unsigned next_tag = (words[i] >> 4) & 0xF;
1913
unsigned num_quad_words = midgard_tag_props[tag].size;
1914
1915
if (midg_tags[i] && midg_tags[i] != tag) {
1916
fprintf(fp, "\t/* XXX: TAG ERROR branch, got %s expected %s */\n",
1917
midgard_tag_props[tag].name,
1918
midgard_tag_props[midg_tags[i]].name);
1919
}
1920
1921
midg_tags[i] = tag;
1922
1923
/* Check the tag. The idea is to ensure that next_tag is
1924
* *always* recoverable from the disassembly, such that we may
1925
* safely omit printing next_tag. To show this, we first
1926
* consider that next tags are semantically off-byone -- we end
1927
* up parsing tag n during step n+1. So, we ensure after we're
1928
* done disassembling the next tag of the final bundle is BREAK
1929
* and warn otherwise. We also ensure that the next tag is
1930
* never INVALID. Beyond that, since the last tag is checked
1931
* outside the loop, we can check one tag prior. If equal to
1932
* the current tag (which is unique), we're done. Otherwise, we
1933
* print if that tag was > TAG_BREAK, which implies the tag was
1934
* not TAG_BREAK or TAG_INVALID. But we already checked for
1935
* TAG_INVALID, so it's just if the last tag was TAG_BREAK that
1936
* we're silent. So we throw in a print for break-next on at
1937
* the end of the bundle (if it's not the final bundle, which
1938
* we already check for above), disambiguating this case as
1939
* well. Hence in all cases we are unambiguous, QED. */
1940
1941
if (next_tag == TAG_INVALID)
1942
fprintf(fp, "\t/* XXX: invalid next tag */\n");
1943
1944
if (last_next_tag > TAG_BREAK && last_next_tag != tag) {
1945
fprintf(fp, "\t/* XXX: TAG ERROR sequence, got %s expexted %s */\n",
1946
midgard_tag_props[tag].name,
1947
midgard_tag_props[last_next_tag].name);
1948
}
1949
1950
last_next_tag = next_tag;
1951
1952
/* Tags are unique in the following way:
1953
*
1954
* INVALID, BREAK, UNKNOWN_*: verbosely printed
1955
* TEXTURE_4_BARRIER: verified by barrier/!barrier op
1956
* TEXTURE_4_VTX: .vtx tag printed
1957
* TEXTURE_4: tetxure lack of barriers or .vtx
1958
* TAG_LOAD_STORE_4: only load/store
1959
* TAG_ALU_4/8/12/16: by number of instructions/constants
1960
* TAG_ALU_4_8/12/16_WRITEOUT: ^^ with .writeout tag
1961
*/
1962
1963
switch (tag) {
1964
case TAG_TEXTURE_4_VTX ... TAG_TEXTURE_4_BARRIER: {
1965
bool interpipe_aliasing =
1966
midgard_get_quirks(gpu_id) & MIDGARD_INTERPIPE_REG_ALIASING;
1967
1968
print_texture_word(fp, &words[i], tabs,
1969
interpipe_aliasing ? 0 : REG_TEX_BASE,
1970
interpipe_aliasing ? REGISTER_LDST_BASE : REG_TEX_BASE);
1971
break;
1972
}
1973
1974
case TAG_LOAD_STORE_4:
1975
print_load_store_word(fp, &words[i], verbose);
1976
break;
1977
1978
case TAG_ALU_4 ... TAG_ALU_16_WRITEOUT:
1979
branch_forward = print_alu_word(fp, &words[i], num_quad_words, tabs, i + 4*num_quad_words, verbose);
1980
1981
/* TODO: infer/verify me */
1982
if (tag >= TAG_ALU_4_WRITEOUT)
1983
fprintf(fp, "writeout\n");
1984
1985
break;
1986
1987
default:
1988
fprintf(fp, "Unknown word type %u:\n", words[i] & 0xF);
1989
num_quad_words = 1;
1990
print_quad_word(fp, &words[i], tabs);
1991
fprintf(fp, "\n");
1992
break;
1993
}
1994
1995
/* We are parsing per bundle anyway. Add before we start
1996
* breaking out so we don't miss the final bundle. */
1997
1998
midg_stats.bundle_count++;
1999
midg_stats.quadword_count += num_quad_words;
2000
2001
/* Include a synthetic "break" instruction at the end of the
2002
* bundle to signify that if, absent a branch, the shader
2003
* execution will stop here. Stop disassembly at such a break
2004
* based on a heuristic */
2005
2006
if (next_tag == TAG_BREAK) {
2007
if (branch_forward) {
2008
fprintf(fp, "break\n");
2009
} else {
2010
fprintf(fp, "\n");
2011
break;
2012
}
2013
}
2014
2015
fprintf(fp, "\n");
2016
2017
i += 4 * num_quad_words;
2018
}
2019
2020
if (last_next_tag != TAG_BREAK) {
2021
fprintf(fp, "/* XXX: shader ended with tag %s */\n",
2022
midgard_tag_props[last_next_tag].name);
2023
}
2024
2025
free(midg_tags);
2026
2027
/* We computed work_count as max_work_registers, so add one to get the
2028
* count. If no work registers are written, you still have one work
2029
* reported, which is exactly what the hardware expects */
2030
2031
midg_stats.work_count++;
2032
2033
return midg_stats;
2034
}
2035
2036