Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/vc4/vc4_qir.c
4570 views
1
/*
2
* Copyright © 2014 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 "util/u_memory.h"
25
#include "util/ralloc.h"
26
27
#include "vc4_qir.h"
28
#include "vc4_qpu.h"
29
30
struct qir_op_info {
31
const char *name;
32
uint8_t ndst, nsrc;
33
bool has_side_effects;
34
};
35
36
static const struct qir_op_info qir_op_info[] = {
37
[QOP_MOV] = { "mov", 1, 1 },
38
[QOP_FMOV] = { "fmov", 1, 1 },
39
[QOP_MMOV] = { "mmov", 1, 1 },
40
[QOP_FADD] = { "fadd", 1, 2 },
41
[QOP_FSUB] = { "fsub", 1, 2 },
42
[QOP_FMUL] = { "fmul", 1, 2 },
43
[QOP_MUL24] = { "mul24", 1, 2 },
44
[QOP_V8MULD] = {"v8muld", 1, 2 },
45
[QOP_V8MIN] = {"v8min", 1, 2 },
46
[QOP_V8MAX] = {"v8max", 1, 2 },
47
[QOP_V8ADDS] = {"v8adds", 1, 2 },
48
[QOP_V8SUBS] = {"v8subs", 1, 2 },
49
[QOP_FMIN] = { "fmin", 1, 2 },
50
[QOP_FMAX] = { "fmax", 1, 2 },
51
[QOP_FMINABS] = { "fminabs", 1, 2 },
52
[QOP_FMAXABS] = { "fmaxabs", 1, 2 },
53
[QOP_FTOI] = { "ftoi", 1, 1 },
54
[QOP_ITOF] = { "itof", 1, 1 },
55
[QOP_ADD] = { "add", 1, 2 },
56
[QOP_SUB] = { "sub", 1, 2 },
57
[QOP_SHR] = { "shr", 1, 2 },
58
[QOP_ASR] = { "asr", 1, 2 },
59
[QOP_SHL] = { "shl", 1, 2 },
60
[QOP_MIN] = { "min", 1, 2 },
61
[QOP_MIN_NOIMM] = { "min_noimm", 1, 2 },
62
[QOP_MAX] = { "max", 1, 2 },
63
[QOP_AND] = { "and", 1, 2 },
64
[QOP_OR] = { "or", 1, 2 },
65
[QOP_XOR] = { "xor", 1, 2 },
66
[QOP_NOT] = { "not", 1, 1 },
67
68
[QOP_RCP] = { "rcp", 1, 1 },
69
[QOP_RSQ] = { "rsq", 1, 1 },
70
[QOP_EXP2] = { "exp2", 1, 1 },
71
[QOP_LOG2] = { "log2", 1, 1 },
72
[QOP_TLB_COLOR_READ] = { "tlb_color_read", 1, 0 },
73
[QOP_MS_MASK] = { "ms_mask", 0, 1, true },
74
[QOP_VARY_ADD_C] = { "vary_add_c", 1, 1 },
75
76
[QOP_FRAG_Z] = { "frag_z", 1, 0 },
77
[QOP_FRAG_W] = { "frag_w", 1, 0 },
78
79
[QOP_TEX_RESULT] = { "tex_result", 1, 0, true },
80
81
[QOP_THRSW] = { "thrsw", 0, 0, true },
82
83
[QOP_LOAD_IMM] = { "load_imm", 0, 1 },
84
[QOP_LOAD_IMM_U2] = { "load_imm_u2", 0, 1 },
85
[QOP_LOAD_IMM_I2] = { "load_imm_i2", 0, 1 },
86
87
[QOP_ROT_MUL] = { "rot_mul", 0, 2 },
88
89
[QOP_BRANCH] = { "branch", 0, 0, true },
90
[QOP_UNIFORMS_RESET] = { "uniforms_reset", 0, 2, true },
91
};
92
93
static const char *
94
qir_get_op_name(enum qop qop)
95
{
96
if (qop < ARRAY_SIZE(qir_op_info) && qir_op_info[qop].name)
97
return qir_op_info[qop].name;
98
else
99
return "???";
100
}
101
102
int
103
qir_get_non_sideband_nsrc(struct qinst *inst)
104
{
105
assert(qir_op_info[inst->op].name);
106
return qir_op_info[inst->op].nsrc;
107
}
108
109
int
110
qir_get_nsrc(struct qinst *inst)
111
{
112
assert(qir_op_info[inst->op].name);
113
114
int nsrc = qir_get_non_sideband_nsrc(inst);
115
116
/* Normal (non-direct) texture coordinate writes also implicitly load
117
* a uniform for the texture parameters.
118
*/
119
if (qir_is_tex(inst) && inst->dst.file != QFILE_TEX_S_DIRECT)
120
nsrc++;
121
122
return nsrc;
123
}
124
125
/* The sideband uniform for textures gets stored after the normal ALU
126
* arguments.
127
*/
128
int
129
qir_get_tex_uniform_src(struct qinst *inst)
130
{
131
return qir_get_nsrc(inst) - 1;
132
}
133
134
/**
135
* Returns whether the instruction has any side effects that must be
136
* preserved.
137
*/
138
bool
139
qir_has_side_effects(struct vc4_compile *c, struct qinst *inst)
140
{
141
switch (inst->dst.file) {
142
case QFILE_TLB_Z_WRITE:
143
case QFILE_TLB_COLOR_WRITE:
144
case QFILE_TLB_COLOR_WRITE_MS:
145
case QFILE_TLB_STENCIL_SETUP:
146
case QFILE_TEX_S_DIRECT:
147
case QFILE_TEX_S:
148
case QFILE_TEX_T:
149
case QFILE_TEX_R:
150
case QFILE_TEX_B:
151
return true;
152
default:
153
break;
154
}
155
156
return qir_op_info[inst->op].has_side_effects;
157
}
158
159
bool
160
qir_has_side_effect_reads(struct vc4_compile *c, struct qinst *inst)
161
{
162
/* We can dead-code eliminate varyings, because we only tell the VS
163
* about the live ones at the end. But we have to preserve the
164
* point/line coordinates reads, because they're generated by
165
* fixed-function hardware.
166
*/
167
for (int i = 0; i < qir_get_nsrc(inst); i++) {
168
if (inst->src[i].file == QFILE_VARY &&
169
c->input_slots[inst->src[i].index].slot == 0xff) {
170
return true;
171
}
172
173
if (inst->src[i].file == QFILE_VPM)
174
return true;
175
}
176
177
if (inst->dst.file == QFILE_VPM)
178
return true;
179
180
return false;
181
}
182
183
bool
184
qir_has_uniform_read(struct qinst *inst)
185
{
186
for (int i = 0; i < qir_get_nsrc(inst); i++) {
187
if (inst->src[i].file == QFILE_UNIF)
188
return true;
189
}
190
191
return false;
192
}
193
194
bool
195
qir_is_mul(struct qinst *inst)
196
{
197
switch (inst->op) {
198
case QOP_MMOV:
199
case QOP_FMUL:
200
case QOP_MUL24:
201
case QOP_V8MULD:
202
case QOP_V8MIN:
203
case QOP_V8MAX:
204
case QOP_V8ADDS:
205
case QOP_V8SUBS:
206
case QOP_ROT_MUL:
207
return true;
208
default:
209
return false;
210
}
211
}
212
213
bool
214
qir_is_float_input(struct qinst *inst)
215
{
216
switch (inst->op) {
217
case QOP_FMOV:
218
case QOP_FMUL:
219
case QOP_FADD:
220
case QOP_FSUB:
221
case QOP_FMIN:
222
case QOP_FMAX:
223
case QOP_FMINABS:
224
case QOP_FMAXABS:
225
case QOP_FTOI:
226
return true;
227
default:
228
return false;
229
}
230
}
231
232
bool
233
qir_is_raw_mov(struct qinst *inst)
234
{
235
return ((inst->op == QOP_MOV ||
236
inst->op == QOP_FMOV ||
237
inst->op == QOP_MMOV) &&
238
inst->cond == QPU_COND_ALWAYS &&
239
!inst->dst.pack &&
240
!inst->src[0].pack);
241
}
242
243
bool
244
qir_is_tex(struct qinst *inst)
245
{
246
switch (inst->dst.file) {
247
case QFILE_TEX_S_DIRECT:
248
case QFILE_TEX_S:
249
case QFILE_TEX_T:
250
case QFILE_TEX_R:
251
case QFILE_TEX_B:
252
return true;
253
default:
254
return false;
255
}
256
}
257
258
bool
259
qir_has_implicit_tex_uniform(struct qinst *inst)
260
{
261
switch (inst->dst.file) {
262
case QFILE_TEX_S:
263
case QFILE_TEX_T:
264
case QFILE_TEX_R:
265
case QFILE_TEX_B:
266
return true;
267
default:
268
return false;
269
}
270
}
271
272
bool
273
qir_depends_on_flags(struct qinst *inst)
274
{
275
if (inst->op == QOP_BRANCH) {
276
return inst->cond != QPU_COND_BRANCH_ALWAYS;
277
} else {
278
return (inst->cond != QPU_COND_ALWAYS &&
279
inst->cond != QPU_COND_NEVER);
280
}
281
}
282
283
bool
284
qir_writes_r4(struct qinst *inst)
285
{
286
switch (inst->op) {
287
case QOP_TEX_RESULT:
288
case QOP_TLB_COLOR_READ:
289
case QOP_RCP:
290
case QOP_RSQ:
291
case QOP_EXP2:
292
case QOP_LOG2:
293
return true;
294
default:
295
return false;
296
}
297
}
298
299
uint8_t
300
qir_channels_written(struct qinst *inst)
301
{
302
if (qir_is_mul(inst)) {
303
switch (inst->dst.pack) {
304
case QPU_PACK_MUL_NOP:
305
case QPU_PACK_MUL_8888:
306
return 0xf;
307
case QPU_PACK_MUL_8A:
308
return 0x1;
309
case QPU_PACK_MUL_8B:
310
return 0x2;
311
case QPU_PACK_MUL_8C:
312
return 0x4;
313
case QPU_PACK_MUL_8D:
314
return 0x8;
315
}
316
} else {
317
switch (inst->dst.pack) {
318
case QPU_PACK_A_NOP:
319
case QPU_PACK_A_8888:
320
case QPU_PACK_A_8888_SAT:
321
case QPU_PACK_A_32_SAT:
322
return 0xf;
323
case QPU_PACK_A_8A:
324
case QPU_PACK_A_8A_SAT:
325
return 0x1;
326
case QPU_PACK_A_8B:
327
case QPU_PACK_A_8B_SAT:
328
return 0x2;
329
case QPU_PACK_A_8C:
330
case QPU_PACK_A_8C_SAT:
331
return 0x4;
332
case QPU_PACK_A_8D:
333
case QPU_PACK_A_8D_SAT:
334
return 0x8;
335
case QPU_PACK_A_16A:
336
case QPU_PACK_A_16A_SAT:
337
return 0x3;
338
case QPU_PACK_A_16B:
339
case QPU_PACK_A_16B_SAT:
340
return 0xc;
341
}
342
}
343
unreachable("Bad pack field");
344
}
345
346
char *
347
qir_describe_uniform(enum quniform_contents contents, uint32_t data,
348
const uint32_t *uniforms)
349
{
350
static const char *quniform_names[] = {
351
[QUNIFORM_VIEWPORT_X_SCALE] = "vp_x_scale",
352
[QUNIFORM_VIEWPORT_Y_SCALE] = "vp_y_scale",
353
[QUNIFORM_VIEWPORT_Z_OFFSET] = "vp_z_offset",
354
[QUNIFORM_VIEWPORT_Z_SCALE] = "vp_z_scale",
355
[QUNIFORM_TEXTURE_CONFIG_P0] = "tex_p0",
356
[QUNIFORM_TEXTURE_CONFIG_P1] = "tex_p1",
357
[QUNIFORM_TEXTURE_CONFIG_P2] = "tex_p2",
358
[QUNIFORM_TEXTURE_FIRST_LEVEL] = "tex_first_level",
359
};
360
361
switch (contents) {
362
case QUNIFORM_CONSTANT:
363
return ralloc_asprintf(NULL, "0x%08x / %f", data, uif(data));
364
case QUNIFORM_UNIFORM:
365
if (uniforms) {
366
uint32_t unif = uniforms[data];
367
return ralloc_asprintf(NULL, "unif[%d] = 0x%08x / %f",
368
data, unif, uif(unif));
369
} else {
370
return ralloc_asprintf(NULL, "unif[%d]", data);
371
}
372
373
case QUNIFORM_TEXTURE_CONFIG_P0:
374
case QUNIFORM_TEXTURE_CONFIG_P1:
375
case QUNIFORM_TEXTURE_CONFIG_P2:
376
case QUNIFORM_TEXTURE_FIRST_LEVEL:
377
return ralloc_asprintf(NULL, "%s[%d]",
378
quniform_names[contents], data);
379
380
default:
381
if (contents < ARRAY_SIZE(quniform_names) &&
382
quniform_names[contents]) {
383
return ralloc_asprintf(NULL, "%s",
384
quniform_names[contents]);
385
} else {
386
return ralloc_asprintf(NULL, "??? %d", contents);
387
}
388
}
389
}
390
391
static void
392
qir_print_reg(struct vc4_compile *c, struct qreg reg, bool write)
393
{
394
static const char *files[] = {
395
[QFILE_TEMP] = "t",
396
[QFILE_VARY] = "v",
397
[QFILE_TLB_COLOR_WRITE] = "tlb_c",
398
[QFILE_TLB_COLOR_WRITE_MS] = "tlb_c_ms",
399
[QFILE_TLB_Z_WRITE] = "tlb_z",
400
[QFILE_TLB_STENCIL_SETUP] = "tlb_stencil",
401
[QFILE_FRAG_X] = "frag_x",
402
[QFILE_FRAG_Y] = "frag_y",
403
[QFILE_FRAG_REV_FLAG] = "frag_rev_flag",
404
[QFILE_QPU_ELEMENT] = "elem",
405
[QFILE_TEX_S_DIRECT] = "tex_s_direct",
406
[QFILE_TEX_S] = "tex_s",
407
[QFILE_TEX_T] = "tex_t",
408
[QFILE_TEX_R] = "tex_r",
409
[QFILE_TEX_B] = "tex_b",
410
};
411
412
switch (reg.file) {
413
414
case QFILE_NULL:
415
fprintf(stderr, "null");
416
break;
417
418
case QFILE_LOAD_IMM:
419
fprintf(stderr, "0x%08x (%f)", reg.index, uif(reg.index));
420
break;
421
422
case QFILE_SMALL_IMM:
423
if ((int)reg.index >= -16 && (int)reg.index <= 15)
424
fprintf(stderr, "%d", reg.index);
425
else
426
fprintf(stderr, "%f", uif(reg.index));
427
break;
428
429
case QFILE_VPM:
430
if (write) {
431
fprintf(stderr, "vpm");
432
} else {
433
fprintf(stderr, "vpm%d.%d",
434
reg.index / 4, reg.index % 4);
435
}
436
break;
437
438
case QFILE_TLB_COLOR_WRITE:
439
case QFILE_TLB_COLOR_WRITE_MS:
440
case QFILE_TLB_Z_WRITE:
441
case QFILE_TLB_STENCIL_SETUP:
442
case QFILE_TEX_S_DIRECT:
443
case QFILE_TEX_S:
444
case QFILE_TEX_T:
445
case QFILE_TEX_R:
446
case QFILE_TEX_B:
447
fprintf(stderr, "%s", files[reg.file]);
448
break;
449
450
case QFILE_UNIF: {
451
char *desc = qir_describe_uniform(c->uniform_contents[reg.index],
452
c->uniform_data[reg.index],
453
NULL);
454
fprintf(stderr, "u%d (%s)", reg.index, desc);
455
ralloc_free(desc);
456
break;
457
}
458
459
default:
460
fprintf(stderr, "%s%d", files[reg.file], reg.index);
461
break;
462
}
463
}
464
465
void
466
qir_dump_inst(struct vc4_compile *c, struct qinst *inst)
467
{
468
fprintf(stderr, "%s", qir_get_op_name(inst->op));
469
if (inst->op == QOP_BRANCH)
470
vc4_qpu_disasm_cond_branch(stderr, inst->cond);
471
else
472
vc4_qpu_disasm_cond(stderr, inst->cond);
473
if (inst->sf)
474
fprintf(stderr, ".sf");
475
fprintf(stderr, " ");
476
477
if (inst->op != QOP_BRANCH) {
478
qir_print_reg(c, inst->dst, true);
479
if (inst->dst.pack) {
480
if (inst->dst.pack) {
481
if (qir_is_mul(inst))
482
vc4_qpu_disasm_pack_mul(stderr, inst->dst.pack);
483
else
484
vc4_qpu_disasm_pack_a(stderr, inst->dst.pack);
485
}
486
}
487
}
488
489
for (int i = 0; i < qir_get_nsrc(inst); i++) {
490
fprintf(stderr, ", ");
491
qir_print_reg(c, inst->src[i], false);
492
vc4_qpu_disasm_unpack(stderr, inst->src[i].pack);
493
}
494
}
495
496
void
497
qir_dump(struct vc4_compile *c)
498
{
499
int ip = 0;
500
int pressure = 0;
501
502
qir_for_each_block(block, c) {
503
fprintf(stderr, "BLOCK %d:\n", block->index);
504
qir_for_each_inst(inst, block) {
505
if (c->temp_start) {
506
bool first = true;
507
508
fprintf(stderr, "%3d ", pressure);
509
510
for (int i = 0; i < c->num_temps; i++) {
511
if (c->temp_start[i] != ip)
512
continue;
513
514
if (first) {
515
first = false;
516
} else {
517
fprintf(stderr, ", ");
518
}
519
fprintf(stderr, "S%4d", i);
520
pressure++;
521
}
522
523
if (first)
524
fprintf(stderr, " ");
525
else
526
fprintf(stderr, " ");
527
}
528
529
if (c->temp_end) {
530
bool first = true;
531
532
for (int i = 0; i < c->num_temps; i++) {
533
if (c->temp_end[i] != ip)
534
continue;
535
536
if (first) {
537
first = false;
538
} else {
539
fprintf(stderr, ", ");
540
}
541
fprintf(stderr, "E%4d", i);
542
pressure--;
543
}
544
545
if (first)
546
fprintf(stderr, " ");
547
else
548
fprintf(stderr, " ");
549
}
550
551
qir_dump_inst(c, inst);
552
fprintf(stderr, "\n");
553
ip++;
554
}
555
if (block->successors[1]) {
556
fprintf(stderr, "-> BLOCK %d, %d\n",
557
block->successors[0]->index,
558
block->successors[1]->index);
559
} else if (block->successors[0]) {
560
fprintf(stderr, "-> BLOCK %d\n",
561
block->successors[0]->index);
562
}
563
}
564
}
565
566
struct qreg
567
qir_get_temp(struct vc4_compile *c)
568
{
569
struct qreg reg;
570
571
reg.file = QFILE_TEMP;
572
reg.index = c->num_temps++;
573
reg.pack = 0;
574
575
if (c->num_temps > c->defs_array_size) {
576
uint32_t old_size = c->defs_array_size;
577
c->defs_array_size = MAX2(old_size * 2, 16);
578
c->defs = reralloc(c, c->defs, struct qinst *,
579
c->defs_array_size);
580
memset(&c->defs[old_size], 0,
581
sizeof(c->defs[0]) * (c->defs_array_size - old_size));
582
}
583
584
return reg;
585
}
586
587
struct qinst *
588
qir_inst(enum qop op, struct qreg dst, struct qreg src0, struct qreg src1)
589
{
590
struct qinst *inst = CALLOC_STRUCT(qinst);
591
592
inst->op = op;
593
inst->dst = dst;
594
inst->src[0] = src0;
595
inst->src[1] = src1;
596
inst->cond = QPU_COND_ALWAYS;
597
598
return inst;
599
}
600
601
static void
602
qir_emit(struct vc4_compile *c, struct qinst *inst)
603
{
604
list_addtail(&inst->link, &c->cur_block->instructions);
605
}
606
607
/* Updates inst to write to a new temporary, emits it, and notes the def. */
608
struct qreg
609
qir_emit_def(struct vc4_compile *c, struct qinst *inst)
610
{
611
assert(inst->dst.file == QFILE_NULL);
612
613
inst->dst = qir_get_temp(c);
614
615
if (inst->dst.file == QFILE_TEMP)
616
c->defs[inst->dst.index] = inst;
617
618
qir_emit(c, inst);
619
620
return inst->dst;
621
}
622
623
struct qinst *
624
qir_emit_nondef(struct vc4_compile *c, struct qinst *inst)
625
{
626
if (inst->dst.file == QFILE_TEMP)
627
c->defs[inst->dst.index] = NULL;
628
629
qir_emit(c, inst);
630
631
return inst;
632
}
633
634
bool
635
qir_reg_equals(struct qreg a, struct qreg b)
636
{
637
return a.file == b.file && a.index == b.index && a.pack == b.pack;
638
}
639
640
struct qblock *
641
qir_new_block(struct vc4_compile *c)
642
{
643
struct qblock *block = rzalloc(c, struct qblock);
644
645
list_inithead(&block->instructions);
646
list_inithead(&block->qpu_inst_list);
647
648
block->predecessors = _mesa_set_create(block,
649
_mesa_hash_pointer,
650
_mesa_key_pointer_equal);
651
652
block->index = c->next_block_index++;
653
654
return block;
655
}
656
657
void
658
qir_set_emit_block(struct vc4_compile *c, struct qblock *block)
659
{
660
c->cur_block = block;
661
list_addtail(&block->link, &c->blocks);
662
}
663
664
struct qblock *
665
qir_entry_block(struct vc4_compile *c)
666
{
667
return list_first_entry(&c->blocks, struct qblock, link);
668
}
669
670
struct qblock *
671
qir_exit_block(struct vc4_compile *c)
672
{
673
return list_last_entry(&c->blocks, struct qblock, link);
674
}
675
676
void
677
qir_link_blocks(struct qblock *predecessor, struct qblock *successor)
678
{
679
_mesa_set_add(successor->predecessors, predecessor);
680
if (predecessor->successors[0]) {
681
assert(!predecessor->successors[1]);
682
predecessor->successors[1] = successor;
683
} else {
684
predecessor->successors[0] = successor;
685
}
686
}
687
688
struct vc4_compile *
689
qir_compile_init(void)
690
{
691
struct vc4_compile *c = rzalloc(NULL, struct vc4_compile);
692
693
list_inithead(&c->blocks);
694
qir_set_emit_block(c, qir_new_block(c));
695
c->last_top_block = c->cur_block;
696
697
c->output_position_index = -1;
698
c->output_color_index = -1;
699
c->output_point_size_index = -1;
700
c->output_sample_mask_index = -1;
701
702
c->def_ht = _mesa_hash_table_create(c, _mesa_hash_pointer,
703
_mesa_key_pointer_equal);
704
705
return c;
706
}
707
708
void
709
qir_remove_instruction(struct vc4_compile *c, struct qinst *qinst)
710
{
711
if (qinst->dst.file == QFILE_TEMP)
712
c->defs[qinst->dst.index] = NULL;
713
714
list_del(&qinst->link);
715
free(qinst);
716
}
717
718
struct qreg
719
qir_follow_movs(struct vc4_compile *c, struct qreg reg)
720
{
721
int pack = reg.pack;
722
723
while (reg.file == QFILE_TEMP &&
724
c->defs[reg.index] &&
725
(c->defs[reg.index]->op == QOP_MOV ||
726
c->defs[reg.index]->op == QOP_FMOV ||
727
c->defs[reg.index]->op == QOP_MMOV)&&
728
!c->defs[reg.index]->dst.pack &&
729
!c->defs[reg.index]->src[0].pack) {
730
reg = c->defs[reg.index]->src[0];
731
}
732
733
reg.pack = pack;
734
return reg;
735
}
736
737
void
738
qir_compile_destroy(struct vc4_compile *c)
739
{
740
qir_for_each_block(block, c) {
741
while (!list_is_empty(&block->instructions)) {
742
struct qinst *qinst =
743
list_first_entry(&block->instructions,
744
struct qinst, link);
745
qir_remove_instruction(c, qinst);
746
}
747
}
748
749
ralloc_free(c);
750
}
751
752
const char *
753
qir_get_stage_name(enum qstage stage)
754
{
755
static const char *names[] = {
756
[QSTAGE_FRAG] = "FS",
757
[QSTAGE_VERT] = "VS",
758
[QSTAGE_COORD] = "CS",
759
};
760
761
return names[stage];
762
}
763
764
struct qreg
765
qir_uniform(struct vc4_compile *c,
766
enum quniform_contents contents,
767
uint32_t data)
768
{
769
for (int i = 0; i < c->num_uniforms; i++) {
770
if (c->uniform_contents[i] == contents &&
771
c->uniform_data[i] == data) {
772
return qir_reg(QFILE_UNIF, i);
773
}
774
}
775
776
uint32_t uniform = c->num_uniforms++;
777
778
if (uniform >= c->uniform_array_size) {
779
c->uniform_array_size = MAX2(MAX2(16, uniform + 1),
780
c->uniform_array_size * 2);
781
782
c->uniform_data = reralloc(c, c->uniform_data,
783
uint32_t,
784
c->uniform_array_size);
785
c->uniform_contents = reralloc(c, c->uniform_contents,
786
enum quniform_contents,
787
c->uniform_array_size);
788
}
789
790
c->uniform_contents[uniform] = contents;
791
c->uniform_data[uniform] = data;
792
793
return qir_reg(QFILE_UNIF, uniform);
794
}
795
796
void
797
qir_SF(struct vc4_compile *c, struct qreg src)
798
{
799
struct qinst *last_inst = NULL;
800
801
if (!list_is_empty(&c->cur_block->instructions))
802
last_inst = (struct qinst *)c->cur_block->instructions.prev;
803
804
/* We don't have any way to guess which kind of MOV is implied. */
805
assert(!src.pack);
806
807
if (src.file != QFILE_TEMP ||
808
!c->defs[src.index] ||
809
last_inst != c->defs[src.index]) {
810
last_inst = qir_MOV_dest(c, qir_reg(QFILE_NULL, 0), src);
811
last_inst = (struct qinst *)c->cur_block->instructions.prev;
812
}
813
last_inst->sf = true;
814
}
815
816
#define OPTPASS(func) \
817
do { \
818
bool stage_progress = func(c); \
819
if (stage_progress) { \
820
progress = true; \
821
if (print_opt_debug) { \
822
fprintf(stderr, \
823
"QIR opt pass %2d: %s progress\n", \
824
pass, #func); \
825
} \
826
qir_validate(c); \
827
} \
828
} while (0)
829
830
void
831
qir_optimize(struct vc4_compile *c)
832
{
833
bool print_opt_debug = false;
834
int pass = 1;
835
836
while (true) {
837
bool progress = false;
838
839
OPTPASS(qir_opt_algebraic);
840
OPTPASS(qir_opt_constant_folding);
841
OPTPASS(qir_opt_copy_propagation);
842
OPTPASS(qir_opt_peephole_sf);
843
OPTPASS(qir_opt_dead_code);
844
OPTPASS(qir_opt_small_immediates);
845
OPTPASS(qir_opt_vpm);
846
OPTPASS(qir_opt_coalesce_ff_writes);
847
848
if (!progress)
849
break;
850
851
pass++;
852
}
853
}
854
855