OSDN Git Service

gallium/drivers/svga: Use unsigned for loop index
[android-x86/external-mesa.git] / src / gallium / drivers / vc4 / vc4_qir.c
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         bool multi_instruction;
35 };
36
37 static const struct qir_op_info qir_op_info[] = {
38         [QOP_MOV] = { "mov", 1, 1 },
39         [QOP_FMOV] = { "fmov", 1, 1 },
40         [QOP_MMOV] = { "mmov", 1, 1 },
41         [QOP_FADD] = { "fadd", 1, 2 },
42         [QOP_FSUB] = { "fsub", 1, 2 },
43         [QOP_FMUL] = { "fmul", 1, 2 },
44         [QOP_MUL24] = { "mul24", 1, 2 },
45         [QOP_V8MULD] = {"v8muld", 1, 2 },
46         [QOP_V8MIN] = {"v8min", 1, 2 },
47         [QOP_V8MAX] = {"v8max", 1, 2 },
48         [QOP_V8ADDS] = {"v8adds", 1, 2 },
49         [QOP_V8SUBS] = {"v8subs", 1, 2 },
50         [QOP_FMIN] = { "fmin", 1, 2 },
51         [QOP_FMAX] = { "fmax", 1, 2 },
52         [QOP_FMINABS] = { "fminabs", 1, 2 },
53         [QOP_FMAXABS] = { "fmaxabs", 1, 2 },
54         [QOP_FTOI] = { "ftoi", 1, 1 },
55         [QOP_ITOF] = { "itof", 1, 1 },
56         [QOP_ADD] = { "add", 1, 2 },
57         [QOP_SUB] = { "sub", 1, 2 },
58         [QOP_SHR] = { "shr", 1, 2 },
59         [QOP_ASR] = { "asr", 1, 2 },
60         [QOP_SHL] = { "shl", 1, 2 },
61         [QOP_MIN] = { "min", 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_SEL_X_0_NS] = { "fsel_x_0_ns", 1, 1, false, true },
69         [QOP_SEL_X_0_NC] = { "fsel_x_0_nc", 1, 1, false, true },
70         [QOP_SEL_X_0_ZS] = { "fsel_x_0_zs", 1, 1, false, true },
71         [QOP_SEL_X_0_ZC] = { "fsel_x_0_zc", 1, 1, false, true },
72         [QOP_SEL_X_0_CS] = { "fsel_x_0_cs", 1, 1, false, true },
73         [QOP_SEL_X_0_CC] = { "fsel_x_0_cc", 1, 1, false, true },
74         [QOP_SEL_X_Y_NS] = { "fsel_x_y_ns", 1, 2, false, true },
75         [QOP_SEL_X_Y_NC] = { "fsel_x_y_nc", 1, 2, false, true },
76         [QOP_SEL_X_Y_ZS] = { "fsel_x_y_zs", 1, 2, false, true },
77         [QOP_SEL_X_Y_ZC] = { "fsel_x_y_zc", 1, 2, false, true },
78         [QOP_SEL_X_Y_CS] = { "fsel_x_y_cs", 1, 2, false, true },
79         [QOP_SEL_X_Y_CC] = { "fsel_x_y_cc", 1, 2, false, true },
80
81         [QOP_RCP] = { "rcp", 1, 1, false, true },
82         [QOP_RSQ] = { "rsq", 1, 1, false, true },
83         [QOP_EXP2] = { "exp2", 1, 2, false, true },
84         [QOP_LOG2] = { "log2", 1, 2, false, true },
85         [QOP_TLB_DISCARD_SETUP] = { "discard", 0, 1, true },
86         [QOP_TLB_STENCIL_SETUP] = { "tlb_stencil_setup", 0, 1, true },
87         [QOP_TLB_Z_WRITE] = { "tlb_z", 0, 1, true },
88         [QOP_TLB_COLOR_WRITE] = { "tlb_color", 0, 1, true },
89         [QOP_TLB_COLOR_WRITE_MS] = { "tlb_color_ms", 0, 1, true },
90         [QOP_TLB_COLOR_READ] = { "tlb_color_read", 1, 0 },
91         [QOP_MS_MASK] = { "ms_mask", 0, 1, true },
92         [QOP_VARY_ADD_C] = { "vary_add_c", 1, 1 },
93
94         [QOP_FRAG_X] = { "frag_x", 1, 0 },
95         [QOP_FRAG_Y] = { "frag_y", 1, 0 },
96         [QOP_FRAG_Z] = { "frag_z", 1, 0 },
97         [QOP_FRAG_W] = { "frag_w", 1, 0 },
98         [QOP_FRAG_REV_FLAG] = { "frag_rev_flag", 1, 0 },
99
100         [QOP_TEX_S] = { "tex_s", 0, 2 },
101         [QOP_TEX_T] = { "tex_t", 0, 2 },
102         [QOP_TEX_R] = { "tex_r", 0, 2 },
103         [QOP_TEX_B] = { "tex_b", 0, 2 },
104         [QOP_TEX_DIRECT] = { "tex_direct", 0, 2 },
105         [QOP_TEX_RESULT] = { "tex_result", 1, 0, true },
106 };
107
108 static const char *
109 qir_get_op_name(enum qop qop)
110 {
111         if (qop < ARRAY_SIZE(qir_op_info) && qir_op_info[qop].name)
112                 return qir_op_info[qop].name;
113         else
114                 return "???";
115 }
116
117 int
118 qir_get_op_nsrc(enum qop qop)
119 {
120         if (qop < ARRAY_SIZE(qir_op_info) && qir_op_info[qop].name)
121                 return qir_op_info[qop].nsrc;
122         else
123                 abort();
124 }
125
126 /**
127  * Returns whether the instruction has any side effects that must be
128  * preserved.
129  */
130 bool
131 qir_has_side_effects(struct vc4_compile *c, struct qinst *inst)
132 {
133         return qir_op_info[inst->op].has_side_effects;
134 }
135
136 bool
137 qir_has_side_effect_reads(struct vc4_compile *c, struct qinst *inst)
138 {
139         /* We can dead-code eliminate varyings, because we only tell the VS
140          * about the live ones at the end.  But we have to preserve the
141          * point/line coordinates reads, because they're generated by
142          * fixed-function hardware.
143          */
144         for (int i = 0; i < qir_get_op_nsrc(inst->op); i++) {
145                 if (inst->src[i].file == QFILE_VARY &&
146                     c->input_slots[inst->src[i].index].slot == 0xff) {
147                         return true;
148                 }
149
150                 if (inst->src[i].file == QFILE_VPM)
151                         return true;
152         }
153
154         if (inst->dst.file == QFILE_VPM)
155                 return true;
156
157         return false;
158 }
159
160 bool
161 qir_is_multi_instruction(struct qinst *inst)
162 {
163         return qir_op_info[inst->op].multi_instruction;
164 }
165
166 bool
167 qir_is_mul(struct qinst *inst)
168 {
169         switch (inst->op) {
170         case QOP_MMOV:
171         case QOP_FMUL:
172         case QOP_MUL24:
173         case QOP_V8MULD:
174         case QOP_V8MIN:
175         case QOP_V8MAX:
176         case QOP_V8ADDS:
177         case QOP_V8SUBS:
178                 return true;
179         default:
180                 return false;
181         }
182 }
183
184 bool
185 qir_is_float_input(struct qinst *inst)
186 {
187         switch (inst->op) {
188         case QOP_FMOV:
189         case QOP_FMUL:
190         case QOP_FADD:
191         case QOP_FSUB:
192         case QOP_FMIN:
193         case QOP_FMAX:
194         case QOP_FMINABS:
195         case QOP_FMAXABS:
196         case QOP_FTOI:
197                 return true;
198         default:
199                 return false;
200         }
201 }
202
203 bool
204 qir_is_raw_mov(struct qinst *inst)
205 {
206         return ((inst->op == QOP_MOV ||
207                  inst->op == QOP_FMOV ||
208                  inst->op == QOP_MMOV) &&
209                 !inst->dst.pack &&
210                 !inst->src[0].pack);
211 }
212
213 bool
214 qir_is_tex(struct qinst *inst)
215 {
216         return inst->op >= QOP_TEX_S && inst->op <= QOP_TEX_DIRECT;
217 }
218
219 bool
220 qir_depends_on_flags(struct qinst *inst)
221 {
222         switch (inst->op) {
223         case QOP_SEL_X_0_NS:
224         case QOP_SEL_X_0_NC:
225         case QOP_SEL_X_0_ZS:
226         case QOP_SEL_X_0_ZC:
227         case QOP_SEL_X_0_CS:
228         case QOP_SEL_X_0_CC:
229         case QOP_SEL_X_Y_NS:
230         case QOP_SEL_X_Y_NC:
231         case QOP_SEL_X_Y_ZS:
232         case QOP_SEL_X_Y_ZC:
233         case QOP_SEL_X_Y_CS:
234         case QOP_SEL_X_Y_CC:
235                 return true;
236         default:
237                 return false;
238         }
239 }
240
241 bool
242 qir_writes_r4(struct qinst *inst)
243 {
244         switch (inst->op) {
245         case QOP_TEX_RESULT:
246         case QOP_TLB_COLOR_READ:
247         case QOP_RCP:
248         case QOP_RSQ:
249         case QOP_EXP2:
250         case QOP_LOG2:
251                 return true;
252         default:
253                 return false;
254         }
255 }
256
257 static void
258 qir_print_reg(struct vc4_compile *c, struct qreg reg, bool write)
259 {
260         static const char *files[] = {
261                 [QFILE_TEMP] = "t",
262                 [QFILE_VARY] = "v",
263                 [QFILE_UNIF] = "u",
264         };
265
266         if (reg.file == QFILE_NULL) {
267                 fprintf(stderr, "null");
268         } else if (reg.file == QFILE_SMALL_IMM) {
269                 if ((int)reg.index >= -16 && (int)reg.index <= 15)
270                         fprintf(stderr, "%d", reg.index);
271                 else
272                         fprintf(stderr, "%f", uif(reg.index));
273         } else if (reg.file == QFILE_VPM) {
274                 if (write) {
275                         fprintf(stderr, "vpm");
276                 } else {
277                         fprintf(stderr, "vpm%d.%d",
278                                 reg.index / 4, reg.index % 4);
279                 }
280         } else {
281                 fprintf(stderr, "%s%d", files[reg.file], reg.index);
282         }
283
284         if (reg.file == QFILE_UNIF &&
285             c->uniform_contents[reg.index] == QUNIFORM_CONSTANT) {
286                 fprintf(stderr, " (0x%08x / %f)",
287                         c->uniform_data[reg.index],
288                         uif(c->uniform_data[reg.index]));
289         }
290 }
291
292 void
293 qir_dump_inst(struct vc4_compile *c, struct qinst *inst)
294 {
295         fprintf(stderr, "%s%s ",
296                 qir_get_op_name(inst->op),
297                 inst->sf ? ".sf" : "");
298
299         qir_print_reg(c, inst->dst, true);
300         if (inst->dst.pack) {
301                 if (inst->dst.pack) {
302                         if (qir_is_mul(inst))
303                                 vc4_qpu_disasm_pack_mul(stderr, inst->dst.pack);
304                         else
305                                 vc4_qpu_disasm_pack_a(stderr, inst->dst.pack);
306                 }
307         }
308         for (int i = 0; i < qir_get_op_nsrc(inst->op); i++) {
309                 fprintf(stderr, ", ");
310                 qir_print_reg(c, inst->src[i], false);
311                 vc4_qpu_disasm_unpack(stderr, inst->src[i].pack);
312         }
313 }
314
315 void
316 qir_dump(struct vc4_compile *c)
317 {
318         list_for_each_entry(struct qinst, inst, &c->instructions, link) {
319                 qir_dump_inst(c, inst);
320                 fprintf(stderr, "\n");
321         }
322 }
323
324 struct qreg
325 qir_get_temp(struct vc4_compile *c)
326 {
327         struct qreg reg;
328
329         reg.file = QFILE_TEMP;
330         reg.index = c->num_temps++;
331         reg.pack = 0;
332
333         if (c->num_temps > c->defs_array_size) {
334                 uint32_t old_size = c->defs_array_size;
335                 c->defs_array_size = MAX2(old_size * 2, 16);
336                 c->defs = reralloc(c, c->defs, struct qinst *,
337                                    c->defs_array_size);
338                 memset(&c->defs[old_size], 0,
339                        sizeof(c->defs[0]) * (c->defs_array_size - old_size));
340         }
341
342         return reg;
343 }
344
345 struct qinst *
346 qir_inst(enum qop op, struct qreg dst, struct qreg src0, struct qreg src1)
347 {
348         struct qinst *inst = CALLOC_STRUCT(qinst);
349
350         inst->op = op;
351         inst->dst = dst;
352         inst->src = calloc(2, sizeof(inst->src[0]));
353         inst->src[0] = src0;
354         inst->src[1] = src1;
355
356         return inst;
357 }
358
359 struct qinst *
360 qir_inst4(enum qop op, struct qreg dst,
361           struct qreg a,
362           struct qreg b,
363           struct qreg c,
364           struct qreg d)
365 {
366         struct qinst *inst = CALLOC_STRUCT(qinst);
367
368         inst->op = op;
369         inst->dst = dst;
370         inst->src = calloc(4, sizeof(*inst->src));
371         inst->src[0] = a;
372         inst->src[1] = b;
373         inst->src[2] = c;
374         inst->src[3] = d;
375
376         return inst;
377 }
378
379 void
380 qir_emit(struct vc4_compile *c, struct qinst *inst)
381 {
382         if (inst->dst.file == QFILE_TEMP)
383                 c->defs[inst->dst.index] = inst;
384
385         qir_emit_nodef(c, inst);
386 }
387
388 bool
389 qir_reg_equals(struct qreg a, struct qreg b)
390 {
391         return a.file == b.file && a.index == b.index;
392 }
393
394 struct vc4_compile *
395 qir_compile_init(void)
396 {
397         struct vc4_compile *c = rzalloc(NULL, struct vc4_compile);
398
399         list_inithead(&c->instructions);
400
401         c->output_position_index = -1;
402         c->output_color_index = -1;
403         c->output_point_size_index = -1;
404         c->output_sample_mask_index = -1;
405
406         c->def_ht = _mesa_hash_table_create(c, _mesa_hash_pointer,
407                                             _mesa_key_pointer_equal);
408
409         return c;
410 }
411
412 void
413 qir_remove_instruction(struct vc4_compile *c, struct qinst *qinst)
414 {
415         if (qinst->dst.file == QFILE_TEMP)
416                 c->defs[qinst->dst.index] = NULL;
417
418         list_del(&qinst->link);
419         free(qinst->src);
420         free(qinst);
421 }
422
423 struct qreg
424 qir_follow_movs(struct vc4_compile *c, struct qreg reg)
425 {
426         int pack = reg.pack;
427
428         while (reg.file == QFILE_TEMP &&
429                c->defs[reg.index] &&
430                (c->defs[reg.index]->op == QOP_MOV ||
431                 c->defs[reg.index]->op == QOP_FMOV ||
432                 c->defs[reg.index]->op == QOP_MMOV)&&
433                !c->defs[reg.index]->dst.pack &&
434                !c->defs[reg.index]->src[0].pack) {
435                 reg = c->defs[reg.index]->src[0];
436         }
437
438         reg.pack = pack;
439         return reg;
440 }
441
442 void
443 qir_compile_destroy(struct vc4_compile *c)
444 {
445         while (!list_empty(&c->instructions)) {
446                 struct qinst *qinst =
447                         (struct qinst *)c->instructions.next;
448                 qir_remove_instruction(c, qinst);
449         }
450
451         ralloc_free(c);
452 }
453
454 const char *
455 qir_get_stage_name(enum qstage stage)
456 {
457         static const char *names[] = {
458                 [QSTAGE_FRAG] = "FS",
459                 [QSTAGE_VERT] = "VS",
460                 [QSTAGE_COORD] = "CS",
461         };
462
463         return names[stage];
464 }
465
466 struct qreg
467 qir_uniform(struct vc4_compile *c,
468             enum quniform_contents contents,
469             uint32_t data)
470 {
471         for (int i = 0; i < c->num_uniforms; i++) {
472                 if (c->uniform_contents[i] == contents &&
473                     c->uniform_data[i] == data) {
474                         return (struct qreg) { QFILE_UNIF, i };
475                 }
476         }
477
478         uint32_t uniform = c->num_uniforms++;
479         struct qreg u = { QFILE_UNIF, uniform };
480
481         if (uniform >= c->uniform_array_size) {
482                 c->uniform_array_size = MAX2(MAX2(16, uniform + 1),
483                                              c->uniform_array_size * 2);
484
485                 c->uniform_data = reralloc(c, c->uniform_data,
486                                            uint32_t,
487                                            c->uniform_array_size);
488                 c->uniform_contents = reralloc(c, c->uniform_contents,
489                                                enum quniform_contents,
490                                                c->uniform_array_size);
491         }
492
493         c->uniform_contents[uniform] = contents;
494         c->uniform_data[uniform] = data;
495
496         return u;
497 }
498
499 void
500 qir_SF(struct vc4_compile *c, struct qreg src)
501 {
502         struct qinst *last_inst = NULL;
503         if (!list_empty(&c->instructions))
504                 last_inst = (struct qinst *)c->instructions.prev;
505
506         if (!last_inst ||
507             last_inst->dst.file != src.file ||
508             last_inst->dst.index != src.index ||
509             qir_is_multi_instruction(last_inst)) {
510                 src = qir_MOV(c, src);
511                 last_inst = (struct qinst *)c->instructions.prev;
512         }
513         last_inst->sf = true;
514 }
515
516 #define OPTPASS(func)                                                   \
517         do {                                                            \
518                 bool stage_progress = func(c);                          \
519                 if (stage_progress) {                                   \
520                         progress = true;                                \
521                         if (print_opt_debug) {                          \
522                                 fprintf(stderr,                         \
523                                         "QIR opt pass %2d: %s progress\n", \
524                                         pass, #func);                   \
525                         }                                               \
526                 }                                                       \
527         } while (0)
528
529 void
530 qir_optimize(struct vc4_compile *c)
531 {
532         bool print_opt_debug = false;
533         int pass = 1;
534
535         while (true) {
536                 bool progress = false;
537
538                 OPTPASS(qir_opt_algebraic);
539                 OPTPASS(qir_opt_cse);
540                 OPTPASS(qir_opt_constant_folding);
541                 OPTPASS(qir_opt_copy_propagation);
542                 OPTPASS(qir_opt_dead_code);
543                 OPTPASS(qir_opt_small_immediates);
544                 OPTPASS(qir_opt_vpm_writes);
545
546                 if (!progress)
547                         break;
548
549                 pass++;
550         }
551 }