Home | History | Annotate | Download | only in vc4
      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 static void
    347 qir_print_reg(struct vc4_compile *c, struct qreg reg, bool write)
    348 {
    349         static const char *files[] = {
    350                 [QFILE_TEMP] = "t",
    351                 [QFILE_VARY] = "v",
    352                 [QFILE_UNIF] = "u",
    353                 [QFILE_TLB_COLOR_WRITE] = "tlb_c",
    354                 [QFILE_TLB_COLOR_WRITE_MS] = "tlb_c_ms",
    355                 [QFILE_TLB_Z_WRITE] = "tlb_z",
    356                 [QFILE_TLB_STENCIL_SETUP] = "tlb_stencil",
    357                 [QFILE_FRAG_X] = "frag_x",
    358                 [QFILE_FRAG_Y] = "frag_y",
    359                 [QFILE_FRAG_REV_FLAG] = "frag_rev_flag",
    360                 [QFILE_QPU_ELEMENT] = "elem",
    361                 [QFILE_TEX_S_DIRECT] = "tex_s_direct",
    362                 [QFILE_TEX_S] = "tex_s",
    363                 [QFILE_TEX_T] = "tex_t",
    364                 [QFILE_TEX_R] = "tex_r",
    365                 [QFILE_TEX_B] = "tex_b",
    366         };
    367 
    368         switch (reg.file) {
    369 
    370         case QFILE_NULL:
    371                 fprintf(stderr, "null");
    372                 break;
    373 
    374         case QFILE_LOAD_IMM:
    375                 fprintf(stderr, "0x%08x (%f)", reg.index, uif(reg.index));
    376                 break;
    377 
    378         case QFILE_SMALL_IMM:
    379                 if ((int)reg.index >= -16 && (int)reg.index <= 15)
    380                         fprintf(stderr, "%d", reg.index);
    381                 else
    382                         fprintf(stderr, "%f", uif(reg.index));
    383                 break;
    384 
    385         case QFILE_VPM:
    386                 if (write) {
    387                         fprintf(stderr, "vpm");
    388                 } else {
    389                         fprintf(stderr, "vpm%d.%d",
    390                                 reg.index / 4, reg.index % 4);
    391                 }
    392                 break;
    393 
    394         case QFILE_TLB_COLOR_WRITE:
    395         case QFILE_TLB_COLOR_WRITE_MS:
    396         case QFILE_TLB_Z_WRITE:
    397         case QFILE_TLB_STENCIL_SETUP:
    398         case QFILE_TEX_S_DIRECT:
    399         case QFILE_TEX_S:
    400         case QFILE_TEX_T:
    401         case QFILE_TEX_R:
    402         case QFILE_TEX_B:
    403                 fprintf(stderr, "%s", files[reg.file]);
    404                 break;
    405 
    406         default:
    407                 fprintf(stderr, "%s%d", files[reg.file], reg.index);
    408                 break;
    409         }
    410 
    411         if (reg.file == QFILE_UNIF &&
    412             c->uniform_contents[reg.index] == QUNIFORM_CONSTANT) {
    413                 fprintf(stderr, " (0x%08x / %f)",
    414                         c->uniform_data[reg.index],
    415                         uif(c->uniform_data[reg.index]));
    416         }
    417 }
    418 
    419 void
    420 qir_dump_inst(struct vc4_compile *c, struct qinst *inst)
    421 {
    422         fprintf(stderr, "%s", qir_get_op_name(inst->op));
    423         if (inst->op == QOP_BRANCH)
    424                 vc4_qpu_disasm_cond_branch(stderr, inst->cond);
    425         else
    426                 vc4_qpu_disasm_cond(stderr, inst->cond);
    427         if (inst->sf)
    428                 fprintf(stderr, ".sf");
    429         fprintf(stderr, " ");
    430 
    431         if (inst->op != QOP_BRANCH) {
    432                 qir_print_reg(c, inst->dst, true);
    433                 if (inst->dst.pack) {
    434                         if (inst->dst.pack) {
    435                                 if (qir_is_mul(inst))
    436                                         vc4_qpu_disasm_pack_mul(stderr, inst->dst.pack);
    437                                 else
    438                                         vc4_qpu_disasm_pack_a(stderr, inst->dst.pack);
    439                         }
    440                 }
    441         }
    442 
    443         for (int i = 0; i < qir_get_nsrc(inst); i++) {
    444                 fprintf(stderr, ", ");
    445                 qir_print_reg(c, inst->src[i], false);
    446                 vc4_qpu_disasm_unpack(stderr, inst->src[i].pack);
    447         }
    448 }
    449 
    450 void
    451 qir_dump(struct vc4_compile *c)
    452 {
    453         int ip = 0;
    454         int pressure = 0;
    455 
    456         qir_for_each_block(block, c) {
    457                 fprintf(stderr, "BLOCK %d:\n", block->index);
    458                 qir_for_each_inst(inst, block) {
    459                         if (c->temp_start) {
    460                                 bool first = true;
    461 
    462                                 fprintf(stderr, "%3d ", pressure);
    463 
    464                                 for (int i = 0; i < c->num_temps; i++) {
    465                                         if (c->temp_start[i] != ip)
    466                                                 continue;
    467 
    468                                         if (first) {
    469                                                 first = false;
    470                                         } else {
    471                                                 fprintf(stderr, ", ");
    472                                         }
    473                                         fprintf(stderr, "S%4d", i);
    474                                         pressure++;
    475                                 }
    476 
    477                                 if (first)
    478                                         fprintf(stderr, "      ");
    479                                 else
    480                                         fprintf(stderr, " ");
    481                         }
    482 
    483                         if (c->temp_end) {
    484                                 bool first = true;
    485 
    486                                 for (int i = 0; i < c->num_temps; i++) {
    487                                         if (c->temp_end[i] != ip)
    488                                                 continue;
    489 
    490                                         if (first) {
    491                                                 first = false;
    492                                         } else {
    493                                                 fprintf(stderr, ", ");
    494                                         }
    495                                         fprintf(stderr, "E%4d", i);
    496                                         pressure--;
    497                                 }
    498 
    499                                 if (first)
    500                                         fprintf(stderr, "      ");
    501                                 else
    502                                         fprintf(stderr, " ");
    503                         }
    504 
    505                         qir_dump_inst(c, inst);
    506                         fprintf(stderr, "\n");
    507                         ip++;
    508                 }
    509                 if (block->successors[1]) {
    510                         fprintf(stderr, "-> BLOCK %d, %d\n",
    511                                 block->successors[0]->index,
    512                                 block->successors[1]->index);
    513                 } else if (block->successors[0]) {
    514                         fprintf(stderr, "-> BLOCK %d\n",
    515                                 block->successors[0]->index);
    516                 }
    517         }
    518 }
    519 
    520 struct qreg
    521 qir_get_temp(struct vc4_compile *c)
    522 {
    523         struct qreg reg;
    524 
    525         reg.file = QFILE_TEMP;
    526         reg.index = c->num_temps++;
    527         reg.pack = 0;
    528 
    529         if (c->num_temps > c->defs_array_size) {
    530                 uint32_t old_size = c->defs_array_size;
    531                 c->defs_array_size = MAX2(old_size * 2, 16);
    532                 c->defs = reralloc(c, c->defs, struct qinst *,
    533                                    c->defs_array_size);
    534                 memset(&c->defs[old_size], 0,
    535                        sizeof(c->defs[0]) * (c->defs_array_size - old_size));
    536         }
    537 
    538         return reg;
    539 }
    540 
    541 struct qinst *
    542 qir_inst(enum qop op, struct qreg dst, struct qreg src0, struct qreg src1)
    543 {
    544         struct qinst *inst = CALLOC_STRUCT(qinst);
    545 
    546         inst->op = op;
    547         inst->dst = dst;
    548         inst->src[0] = src0;
    549         inst->src[1] = src1;
    550         inst->cond = QPU_COND_ALWAYS;
    551 
    552         return inst;
    553 }
    554 
    555 static void
    556 qir_emit(struct vc4_compile *c, struct qinst *inst)
    557 {
    558         list_addtail(&inst->link, &c->cur_block->instructions);
    559 }
    560 
    561 /* Updates inst to write to a new temporary, emits it, and notes the def. */
    562 struct qreg
    563 qir_emit_def(struct vc4_compile *c, struct qinst *inst)
    564 {
    565         assert(inst->dst.file == QFILE_NULL);
    566 
    567         inst->dst = qir_get_temp(c);
    568 
    569         if (inst->dst.file == QFILE_TEMP)
    570                 c->defs[inst->dst.index] = inst;
    571 
    572         qir_emit(c, inst);
    573 
    574         return inst->dst;
    575 }
    576 
    577 struct qinst *
    578 qir_emit_nondef(struct vc4_compile *c, struct qinst *inst)
    579 {
    580         if (inst->dst.file == QFILE_TEMP)
    581                 c->defs[inst->dst.index] = NULL;
    582 
    583         qir_emit(c, inst);
    584 
    585         return inst;
    586 }
    587 
    588 bool
    589 qir_reg_equals(struct qreg a, struct qreg b)
    590 {
    591         return a.file == b.file && a.index == b.index && a.pack == b.pack;
    592 }
    593 
    594 struct qblock *
    595 qir_new_block(struct vc4_compile *c)
    596 {
    597         struct qblock *block = rzalloc(c, struct qblock);
    598 
    599         list_inithead(&block->instructions);
    600         list_inithead(&block->qpu_inst_list);
    601 
    602         block->predecessors = _mesa_set_create(block,
    603                                                _mesa_hash_pointer,
    604                                                _mesa_key_pointer_equal);
    605 
    606         block->index = c->next_block_index++;
    607 
    608         return block;
    609 }
    610 
    611 void
    612 qir_set_emit_block(struct vc4_compile *c, struct qblock *block)
    613 {
    614         c->cur_block = block;
    615         list_addtail(&block->link, &c->blocks);
    616 }
    617 
    618 struct qblock *
    619 qir_entry_block(struct vc4_compile *c)
    620 {
    621         return list_first_entry(&c->blocks, struct qblock, link);
    622 }
    623 
    624 struct qblock *
    625 qir_exit_block(struct vc4_compile *c)
    626 {
    627         return list_last_entry(&c->blocks, struct qblock, link);
    628 }
    629 
    630 void
    631 qir_link_blocks(struct qblock *predecessor, struct qblock *successor)
    632 {
    633         _mesa_set_add(successor->predecessors, predecessor);
    634         if (predecessor->successors[0]) {
    635                 assert(!predecessor->successors[1]);
    636                 predecessor->successors[1] = successor;
    637         } else {
    638                 predecessor->successors[0] = successor;
    639         }
    640 }
    641 
    642 struct vc4_compile *
    643 qir_compile_init(void)
    644 {
    645         struct vc4_compile *c = rzalloc(NULL, struct vc4_compile);
    646 
    647         list_inithead(&c->blocks);
    648         qir_set_emit_block(c, qir_new_block(c));
    649 
    650         c->output_position_index = -1;
    651         c->output_color_index = -1;
    652         c->output_point_size_index = -1;
    653         c->output_sample_mask_index = -1;
    654 
    655         c->def_ht = _mesa_hash_table_create(c, _mesa_hash_pointer,
    656                                             _mesa_key_pointer_equal);
    657 
    658         return c;
    659 }
    660 
    661 void
    662 qir_remove_instruction(struct vc4_compile *c, struct qinst *qinst)
    663 {
    664         if (qinst->dst.file == QFILE_TEMP)
    665                 c->defs[qinst->dst.index] = NULL;
    666 
    667         list_del(&qinst->link);
    668         free(qinst);
    669 }
    670 
    671 struct qreg
    672 qir_follow_movs(struct vc4_compile *c, struct qreg reg)
    673 {
    674         int pack = reg.pack;
    675 
    676         while (reg.file == QFILE_TEMP &&
    677                c->defs[reg.index] &&
    678                (c->defs[reg.index]->op == QOP_MOV ||
    679                 c->defs[reg.index]->op == QOP_FMOV ||
    680                 c->defs[reg.index]->op == QOP_MMOV)&&
    681                !c->defs[reg.index]->dst.pack &&
    682                !c->defs[reg.index]->src[0].pack) {
    683                 reg = c->defs[reg.index]->src[0];
    684         }
    685 
    686         reg.pack = pack;
    687         return reg;
    688 }
    689 
    690 void
    691 qir_compile_destroy(struct vc4_compile *c)
    692 {
    693         qir_for_each_block(block, c) {
    694                 while (!list_empty(&block->instructions)) {
    695                         struct qinst *qinst =
    696                                 list_first_entry(&block->instructions,
    697                                                  struct qinst, link);
    698                         qir_remove_instruction(c, qinst);
    699                 }
    700         }
    701 
    702         ralloc_free(c);
    703 }
    704 
    705 const char *
    706 qir_get_stage_name(enum qstage stage)
    707 {
    708         static const char *names[] = {
    709                 [QSTAGE_FRAG] = "FS",
    710                 [QSTAGE_VERT] = "VS",
    711                 [QSTAGE_COORD] = "CS",
    712         };
    713 
    714         return names[stage];
    715 }
    716 
    717 struct qreg
    718 qir_uniform(struct vc4_compile *c,
    719             enum quniform_contents contents,
    720             uint32_t data)
    721 {
    722         for (int i = 0; i < c->num_uniforms; i++) {
    723                 if (c->uniform_contents[i] == contents &&
    724                     c->uniform_data[i] == data) {
    725                         return qir_reg(QFILE_UNIF, i);
    726                 }
    727         }
    728 
    729         uint32_t uniform = c->num_uniforms++;
    730 
    731         if (uniform >= c->uniform_array_size) {
    732                 c->uniform_array_size = MAX2(MAX2(16, uniform + 1),
    733                                              c->uniform_array_size * 2);
    734 
    735                 c->uniform_data = reralloc(c, c->uniform_data,
    736                                            uint32_t,
    737                                            c->uniform_array_size);
    738                 c->uniform_contents = reralloc(c, c->uniform_contents,
    739                                                enum quniform_contents,
    740                                                c->uniform_array_size);
    741         }
    742 
    743         c->uniform_contents[uniform] = contents;
    744         c->uniform_data[uniform] = data;
    745 
    746         return qir_reg(QFILE_UNIF, uniform);
    747 }
    748 
    749 void
    750 qir_SF(struct vc4_compile *c, struct qreg src)
    751 {
    752         struct qinst *last_inst = NULL;
    753 
    754         if (!list_empty(&c->cur_block->instructions))
    755                 last_inst = (struct qinst *)c->cur_block->instructions.prev;
    756 
    757         /* We don't have any way to guess which kind of MOV is implied. */
    758         assert(!src.pack);
    759 
    760         if (src.file != QFILE_TEMP ||
    761             !c->defs[src.index] ||
    762             last_inst != c->defs[src.index]) {
    763                 last_inst = qir_MOV_dest(c, qir_reg(QFILE_NULL, 0), src);
    764                 last_inst = (struct qinst *)c->cur_block->instructions.prev;
    765         }
    766         last_inst->sf = true;
    767 }
    768 
    769 #define OPTPASS(func)                                                   \
    770         do {                                                            \
    771                 bool stage_progress = func(c);                          \
    772                 if (stage_progress) {                                   \
    773                         progress = true;                                \
    774                         if (print_opt_debug) {                          \
    775                                 fprintf(stderr,                         \
    776                                         "QIR opt pass %2d: %s progress\n", \
    777                                         pass, #func);                   \
    778                         }                                               \
    779                         qir_validate(c);                                \
    780                 }                                                       \
    781         } while (0)
    782 
    783 void
    784 qir_optimize(struct vc4_compile *c)
    785 {
    786         bool print_opt_debug = false;
    787         int pass = 1;
    788 
    789         while (true) {
    790                 bool progress = false;
    791 
    792                 OPTPASS(qir_opt_algebraic);
    793                 OPTPASS(qir_opt_constant_folding);
    794                 OPTPASS(qir_opt_copy_propagation);
    795                 OPTPASS(qir_opt_peephole_sf);
    796                 OPTPASS(qir_opt_dead_code);
    797                 OPTPASS(qir_opt_small_immediates);
    798                 OPTPASS(qir_opt_vpm);
    799                 OPTPASS(qir_opt_coalesce_ff_writes);
    800 
    801                 if (!progress)
    802                         break;
    803 
    804                 pass++;
    805         }
    806 }
    807