~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/panfrost/midgard/disassemble.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

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