1/*
2 * Copyright © 2016-2017 Broadcom
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include "broadcom/common/v3d_device_info.h"
25#include "v3d_compiler.h"
26
27/* Prints a human-readable description of the uniform reference. */
28void
29vir_dump_uniform(enum quniform_contents contents,
30                 uint32_t data)
31{
32        static const char *quniform_names[] = {
33                [QUNIFORM_ALPHA_REF] = "alpha_ref",
34                [QUNIFORM_VIEWPORT_X_SCALE] = "vp_x_scale",
35                [QUNIFORM_VIEWPORT_Y_SCALE] = "vp_y_scale",
36                [QUNIFORM_VIEWPORT_Z_OFFSET] = "vp_z_offset",
37                [QUNIFORM_VIEWPORT_Z_SCALE] = "vp_z_scale",
38                [QUNIFORM_SHARED_OFFSET] = "shared_offset",
39        };
40
41        switch (contents) {
42        case QUNIFORM_CONSTANT:
43                fprintf(stderr, "0x%08x / %f", data, uif(data));
44                break;
45
46        case QUNIFORM_UNIFORM:
47                fprintf(stderr, "push[%d]", data);
48                break;
49
50        case QUNIFORM_TEXTURE_CONFIG_P1:
51                fprintf(stderr, "tex[%d].p1", data);
52                break;
53
54        case QUNIFORM_TMU_CONFIG_P0:
55                fprintf(stderr, "tex[%d].p0 | 0x%x",
56                        v3d_unit_data_get_unit(data),
57                        v3d_unit_data_get_offset(data));
58                break;
59
60        case QUNIFORM_TMU_CONFIG_P1:
61                fprintf(stderr, "tex[%d].p1 | 0x%x",
62                        v3d_unit_data_get_unit(data),
63                        v3d_unit_data_get_offset(data));
64                break;
65
66        case QUNIFORM_IMAGE_TMU_CONFIG_P0:
67                fprintf(stderr, "img[%d].p0 | 0x%x",
68                        v3d_unit_data_get_unit(data),
69                        v3d_unit_data_get_offset(data));
70                break;
71
72        case QUNIFORM_TEXTURE_WIDTH:
73                fprintf(stderr, "tex[%d].width", data);
74                break;
75        case QUNIFORM_TEXTURE_HEIGHT:
76                fprintf(stderr, "tex[%d].height", data);
77                break;
78        case QUNIFORM_TEXTURE_DEPTH:
79                fprintf(stderr, "tex[%d].depth", data);
80                break;
81        case QUNIFORM_TEXTURE_ARRAY_SIZE:
82                fprintf(stderr, "tex[%d].array_size", data);
83                break;
84        case QUNIFORM_TEXTURE_LEVELS:
85                fprintf(stderr, "tex[%d].levels", data);
86                break;
87
88        case QUNIFORM_IMAGE_WIDTH:
89                fprintf(stderr, "img[%d].width", data);
90                break;
91        case QUNIFORM_IMAGE_HEIGHT:
92                fprintf(stderr, "img[%d].height", data);
93                break;
94        case QUNIFORM_IMAGE_DEPTH:
95                fprintf(stderr, "img[%d].depth", data);
96                break;
97        case QUNIFORM_IMAGE_ARRAY_SIZE:
98                fprintf(stderr, "img[%d].array_size", data);
99                break;
100
101        case QUNIFORM_SPILL_OFFSET:
102                fprintf(stderr, "spill_offset");
103                break;
104
105        case QUNIFORM_SPILL_SIZE_PER_THREAD:
106                fprintf(stderr, "spill_size_per_thread");
107                break;
108
109        case QUNIFORM_UBO_ADDR:
110                fprintf(stderr, "ubo[%d]+0x%x",
111                        v3d_unit_data_get_unit(data),
112                        v3d_unit_data_get_offset(data));
113                break;
114
115        case QUNIFORM_SSBO_OFFSET:
116                fprintf(stderr, "ssbo[%d]", data);
117                break;
118
119        case QUNIFORM_GET_BUFFER_SIZE:
120                fprintf(stderr, "ssbo_size[%d]", data);
121                break;
122
123        case QUNIFORM_NUM_WORK_GROUPS:
124                fprintf(stderr, "num_wg.%c", data < 3 ? "xyz"[data] : '?');
125                break;
126
127        default:
128                if (quniform_contents_is_texture_p0(contents)) {
129                        fprintf(stderr, "tex[%d].p0: 0x%08x",
130                                contents - QUNIFORM_TEXTURE_CONFIG_P0_0,
131                                data);
132                } else if (contents < ARRAY_SIZE(quniform_names) &&
133                           quniform_names[contents]) {
134                        fprintf(stderr, "%s",
135                                quniform_names[contents]);
136                } else {
137                        fprintf(stderr, "%d / 0x%08x", contents, data);
138                }
139        }
140}
141
142static void
143vir_print_reg(struct v3d_compile *c, const struct qinst *inst,
144              struct qreg reg)
145{
146        switch (reg.file) {
147
148        case QFILE_NULL:
149                fprintf(stderr, "null");
150                break;
151
152        case QFILE_LOAD_IMM:
153                fprintf(stderr, "0x%08x (%f)", reg.index, uif(reg.index));
154                break;
155
156        case QFILE_REG:
157                fprintf(stderr, "rf%d", reg.index);
158                break;
159
160        case QFILE_MAGIC:
161                fprintf(stderr, "%s", v3d_qpu_magic_waddr_name(reg.index));
162                break;
163
164        case QFILE_SMALL_IMM: {
165                uint32_t unpacked;
166                bool ok = v3d_qpu_small_imm_unpack(c->devinfo,
167                                                   inst->qpu.raddr_b,
168                                                   &unpacked);
169                assert(ok); (void) ok;
170
171                if ((int)inst->qpu.raddr_b >= -16 &&
172                    (int)inst->qpu.raddr_b <= 15)
173                        fprintf(stderr, "%d", unpacked);
174                else
175                        fprintf(stderr, "%f", uif(unpacked));
176                break;
177        }
178
179        case QFILE_VPM:
180                fprintf(stderr, "vpm%d.%d",
181                        reg.index / 4, reg.index % 4);
182                break;
183
184        case QFILE_TEMP:
185                fprintf(stderr, "t%d", reg.index);
186                break;
187        }
188}
189
190static void
191vir_dump_sig_addr(const struct v3d_device_info *devinfo,
192                  const struct v3d_qpu_instr *instr)
193{
194        if (devinfo->ver < 41)
195                return;
196
197        if (!instr->sig_magic)
198                fprintf(stderr, ".rf%d", instr->sig_addr);
199        else {
200                const char *name = v3d_qpu_magic_waddr_name(instr->sig_addr);
201                if (name)
202                        fprintf(stderr, ".%s", name);
203                else
204                        fprintf(stderr, ".UNKNOWN%d", instr->sig_addr);
205        }
206}
207
208static void
209vir_dump_sig(struct v3d_compile *c, struct qinst *inst)
210{
211        struct v3d_qpu_sig *sig = &inst->qpu.sig;
212
213        if (sig->thrsw)
214                fprintf(stderr, "; thrsw");
215        if (sig->ldvary) {
216                fprintf(stderr, "; ldvary");
217                vir_dump_sig_addr(c->devinfo, &inst->qpu);
218        }
219        if (sig->ldvpm)
220                fprintf(stderr, "; ldvpm");
221        if (sig->ldtmu) {
222                fprintf(stderr, "; ldtmu");
223                vir_dump_sig_addr(c->devinfo, &inst->qpu);
224        }
225        if (sig->ldtlb) {
226                fprintf(stderr, "; ldtlb");
227                vir_dump_sig_addr(c->devinfo, &inst->qpu);
228        }
229        if (sig->ldtlbu) {
230                fprintf(stderr, "; ldtlbu");
231                vir_dump_sig_addr(c->devinfo, &inst->qpu);
232        }
233        if (sig->ldunif)
234                fprintf(stderr, "; ldunif");
235        if (sig->ldunifrf) {
236                fprintf(stderr, "; ldunifrf");
237                vir_dump_sig_addr(c->devinfo, &inst->qpu);
238        }
239        if (sig->ldunifa)
240                fprintf(stderr, "; ldunifa");
241        if (sig->ldunifarf) {
242                fprintf(stderr, "; ldunifarf");
243                vir_dump_sig_addr(c->devinfo, &inst->qpu);
244        }
245        if (sig->wrtmuc)
246                fprintf(stderr, "; wrtmuc");
247}
248
249static void
250vir_dump_alu(struct v3d_compile *c, struct qinst *inst)
251{
252        struct v3d_qpu_instr *instr = &inst->qpu;
253        int nsrc = vir_get_nsrc(inst);
254        enum v3d_qpu_input_unpack unpack[2];
255
256        if (inst->qpu.alu.add.op != V3D_QPU_A_NOP) {
257                fprintf(stderr, "%s", v3d_qpu_add_op_name(instr->alu.add.op));
258                fprintf(stderr, "%s", v3d_qpu_cond_name(instr->flags.ac));
259                fprintf(stderr, "%s", v3d_qpu_pf_name(instr->flags.apf));
260                fprintf(stderr, "%s", v3d_qpu_uf_name(instr->flags.auf));
261                fprintf(stderr, " ");
262
263                vir_print_reg(c, inst, inst->dst);
264                fprintf(stderr, "%s", v3d_qpu_pack_name(instr->alu.add.output_pack));
265
266                unpack[0] = instr->alu.add.a_unpack;
267                unpack[1] = instr->alu.add.b_unpack;
268        } else {
269                fprintf(stderr, "%s", v3d_qpu_mul_op_name(instr->alu.mul.op));
270                fprintf(stderr, "%s", v3d_qpu_cond_name(instr->flags.mc));
271                fprintf(stderr, "%s", v3d_qpu_pf_name(instr->flags.mpf));
272                fprintf(stderr, "%s", v3d_qpu_uf_name(instr->flags.muf));
273                fprintf(stderr, " ");
274
275                vir_print_reg(c, inst, inst->dst);
276                fprintf(stderr, "%s", v3d_qpu_pack_name(instr->alu.mul.output_pack));
277
278                unpack[0] = instr->alu.mul.a_unpack;
279                unpack[1] = instr->alu.mul.b_unpack;
280        }
281
282        for (int i = 0; i < nsrc; i++) {
283                fprintf(stderr, ", ");
284                vir_print_reg(c, inst, inst->src[i]);
285                fprintf(stderr, "%s", v3d_qpu_unpack_name(unpack[i]));
286        }
287
288        vir_dump_sig(c, inst);
289}
290
291void
292vir_dump_inst(struct v3d_compile *c, struct qinst *inst)
293{
294        struct v3d_qpu_instr *instr = &inst->qpu;
295
296        switch (inst->qpu.type) {
297        case V3D_QPU_INSTR_TYPE_ALU:
298                vir_dump_alu(c, inst);
299                break;
300        case V3D_QPU_INSTR_TYPE_BRANCH:
301                fprintf(stderr, "b");
302                if (instr->branch.ub)
303                        fprintf(stderr, "u");
304
305                fprintf(stderr, "%s",
306                        v3d_qpu_branch_cond_name(instr->branch.cond));
307                fprintf(stderr, "%s", v3d_qpu_msfign_name(instr->branch.msfign));
308
309                switch (instr->branch.bdi) {
310                case V3D_QPU_BRANCH_DEST_ABS:
311                        fprintf(stderr, "  zero_addr+0x%08x", instr->branch.offset);
312                        break;
313
314                case V3D_QPU_BRANCH_DEST_REL:
315                        fprintf(stderr, "  %d", instr->branch.offset);
316                        break;
317
318                case V3D_QPU_BRANCH_DEST_LINK_REG:
319                        fprintf(stderr, "  lri");
320                        break;
321
322                case V3D_QPU_BRANCH_DEST_REGFILE:
323                        fprintf(stderr, "  rf%d", instr->branch.raddr_a);
324                        break;
325                }
326
327                if (instr->branch.ub) {
328                        switch (instr->branch.bdu) {
329                        case V3D_QPU_BRANCH_DEST_ABS:
330                                fprintf(stderr, ", a:unif");
331                                break;
332
333                        case V3D_QPU_BRANCH_DEST_REL:
334                                fprintf(stderr, ", r:unif");
335                                break;
336
337                        case V3D_QPU_BRANCH_DEST_LINK_REG:
338                                fprintf(stderr, ", lri");
339                                break;
340
341                        case V3D_QPU_BRANCH_DEST_REGFILE:
342                                fprintf(stderr, ", rf%d", instr->branch.raddr_a);
343                                break;
344                        }
345                }
346                break;
347        }
348
349        if (vir_has_uniform(inst)) {
350                fprintf(stderr, " (");
351                vir_dump_uniform(c->uniform_contents[inst->uniform],
352                                 c->uniform_data[inst->uniform]);
353                fprintf(stderr, ")");
354        }
355}
356
357void
358vir_dump(struct v3d_compile *c)
359{
360        int ip = 0;
361        int pressure = 0;
362
363        vir_for_each_block(block, c) {
364                fprintf(stderr, "BLOCK %d:\n", block->index);
365                vir_for_each_inst(inst, block) {
366                        if (c->live_intervals_valid) {
367                                for (int i = 0; i < c->num_temps; i++) {
368                                        if (c->temp_start[i] == ip)
369                                                pressure++;
370                                }
371
372                                fprintf(stderr, "P%4d ", pressure);
373
374                                bool first = true;
375
376                                for (int i = 0; i < c->num_temps; i++) {
377                                        if (c->temp_start[i] != ip)
378                                                continue;
379
380                                        if (first) {
381                                                first = false;
382                                        } else {
383                                                fprintf(stderr, ", ");
384                                        }
385                                        if (BITSET_TEST(c->spillable, i))
386                                                fprintf(stderr, "S%4d", i);
387                                        else
388                                                fprintf(stderr, "U%4d", i);
389                                }
390
391                                if (first)
392                                        fprintf(stderr, "      ");
393                                else
394                                        fprintf(stderr, " ");
395                        }
396
397                        if (c->live_intervals_valid) {
398                                bool first = true;
399
400                                for (int i = 0; i < c->num_temps; i++) {
401                                        if (c->temp_end[i] != ip)
402                                                continue;
403
404                                        if (first) {
405                                                first = false;
406                                        } else {
407                                                fprintf(stderr, ", ");
408                                        }
409                                        fprintf(stderr, "E%4d", i);
410                                        pressure--;
411                                }
412
413                                if (first)
414                                        fprintf(stderr, "      ");
415                                else
416                                        fprintf(stderr, " ");
417                        }
418
419                        vir_dump_inst(c, inst);
420                        fprintf(stderr, "\n");
421                        ip++;
422                }
423                if (block->successors[1]) {
424                        fprintf(stderr, "-> BLOCK %d, %d\n",
425                                block->successors[0]->index,
426                                block->successors[1]->index);
427                } else if (block->successors[0]) {
428                        fprintf(stderr, "-> BLOCK %d\n",
429                                block->successors[0]->index);
430                }
431        }
432}
433