Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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 <inttypes.h>
  25.  
  26. #include "vc4_context.h"
  27. #include "vc4_qir.h"
  28. #include "vc4_qpu.h"
  29. #include "util/ralloc.h"
  30.  
  31. static void
  32. vc4_dump_program(struct vc4_compile *c)
  33. {
  34.         fprintf(stderr, "%s prog %d/%d QPU:\n",
  35.                 qir_get_stage_name(c->stage),
  36.                 c->program_id, c->variant_id);
  37.  
  38.         for (int i = 0; i < c->qpu_inst_count; i++) {
  39.                 fprintf(stderr, "0x%016"PRIx64" ", c->qpu_insts[i]);
  40.                 vc4_qpu_disasm(&c->qpu_insts[i], 1);
  41.                 fprintf(stderr, "\n");
  42.         }
  43. }
  44.  
  45. static void
  46. queue(struct vc4_compile *c, uint64_t inst)
  47. {
  48.         struct queued_qpu_inst *q = rzalloc(c, struct queued_qpu_inst);
  49.         q->inst = inst;
  50.         insert_at_tail(&c->qpu_inst_list, &q->link);
  51. }
  52.  
  53. static uint64_t *
  54. last_inst(struct vc4_compile *c)
  55. {
  56.         struct queued_qpu_inst *q =
  57.                 (struct queued_qpu_inst *)last_elem(&c->qpu_inst_list);
  58.         return &q->inst;
  59. }
  60.  
  61. static void
  62. set_last_cond_add(struct vc4_compile *c, uint32_t cond)
  63. {
  64.         *last_inst(c) = qpu_set_cond_add(*last_inst(c), cond);
  65. }
  66.  
  67. /**
  68.  * Some special registers can be read from either file, which lets us resolve
  69.  * raddr conflicts without extra MOVs.
  70.  */
  71. static bool
  72. swap_file(struct qpu_reg *src)
  73. {
  74.         switch (src->addr) {
  75.         case QPU_R_UNIF:
  76.         case QPU_R_VARY:
  77.                 if (src->mux == QPU_MUX_SMALL_IMM) {
  78.                         return false;
  79.                 } else {
  80.                         if (src->mux == QPU_MUX_A)
  81.                                 src->mux = QPU_MUX_B;
  82.                         else
  83.                                 src->mux = QPU_MUX_A;
  84.                         return true;
  85.                 }
  86.  
  87.         default:
  88.                 return false;
  89.         }
  90. }
  91.  
  92. /**
  93.  * This is used to resolve the fact that we might register-allocate two
  94.  * different operands of an instruction to the same physical register file
  95.  * even though instructions have only one field for the register file source
  96.  * address.
  97.  *
  98.  * In that case, we need to move one to a temporary that can be used in the
  99.  * instruction, instead.  We reserve ra31/rb31 for this purpose.
  100.  */
  101. static void
  102. fixup_raddr_conflict(struct vc4_compile *c,
  103.                      struct qpu_reg dst,
  104.                      struct qpu_reg *src0, struct qpu_reg *src1)
  105. {
  106.         uint32_t mux0 = src0->mux == QPU_MUX_SMALL_IMM ? QPU_MUX_B : src0->mux;
  107.         uint32_t mux1 = src1->mux == QPU_MUX_SMALL_IMM ? QPU_MUX_B : src1->mux;
  108.  
  109.         if (mux0 <= QPU_MUX_R5 ||
  110.             mux0 != mux1 ||
  111.             (src0->addr == src1->addr &&
  112.              src0->mux == src1->mux)) {
  113.                 return;
  114.         }
  115.  
  116.         if (swap_file(src0) || swap_file(src1))
  117.                 return;
  118.  
  119.         if (mux0 == QPU_MUX_A) {
  120.                 queue(c, qpu_a_MOV(qpu_rb(31), *src1));
  121.                 *src1 = qpu_rb(31);
  122.         } else {
  123.                 queue(c, qpu_a_MOV(qpu_ra(31), *src1));
  124.                 *src1 = qpu_ra(31);
  125.         }
  126. }
  127.  
  128. void
  129. vc4_generate_code(struct vc4_context *vc4, struct vc4_compile *c)
  130. {
  131.         struct qpu_reg *temp_registers = vc4_register_allocate(vc4, c);
  132.         bool discard = false;
  133.         uint32_t inputs_remaining = c->num_inputs;
  134.         uint32_t vpm_read_fifo_count = 0;
  135.         uint32_t vpm_read_offset = 0;
  136.         int last_vpm_read_index = -1;
  137.         /* Map from the QIR ops enum order to QPU unpack bits. */
  138.         static const uint32_t unpack_map[] = {
  139.                 QPU_UNPACK_8A,
  140.                 QPU_UNPACK_8B,
  141.                 QPU_UNPACK_8C,
  142.                 QPU_UNPACK_8D,
  143.                 QPU_UNPACK_16A_TO_F32,
  144.                 QPU_UNPACK_16B_TO_F32,
  145.         };
  146.  
  147.         make_empty_list(&c->qpu_inst_list);
  148.  
  149.         switch (c->stage) {
  150.         case QSTAGE_VERT:
  151.         case QSTAGE_COORD:
  152.                 /* There's a 4-entry FIFO for VPMVCD reads, each of which can
  153.                  * load up to 16 dwords (4 vec4s) per vertex.
  154.                  */
  155.                 while (inputs_remaining) {
  156.                         uint32_t num_entries = MIN2(inputs_remaining, 16);
  157.                         queue(c, qpu_load_imm_ui(qpu_vrsetup(),
  158.                                                  vpm_read_offset |
  159.                                                  0x00001a00 |
  160.                                                  ((num_entries & 0xf) << 20)));
  161.                         inputs_remaining -= num_entries;
  162.                         vpm_read_offset += num_entries;
  163.                         vpm_read_fifo_count++;
  164.                 }
  165.                 assert(vpm_read_fifo_count <= 4);
  166.  
  167.                 queue(c, qpu_load_imm_ui(qpu_vwsetup(), 0x00001a00));
  168.                 break;
  169.         case QSTAGE_FRAG:
  170.                 break;
  171.         }
  172.  
  173.         struct simple_node *node;
  174.         foreach(node, &c->instructions) {
  175.                 struct qinst *qinst = (struct qinst *)node;
  176.  
  177. #if 0
  178.                 fprintf(stderr, "translating qinst to qpu: ");
  179.                 qir_dump_inst(qinst);
  180.                 fprintf(stderr, "\n");
  181. #endif
  182.  
  183.                 static const struct {
  184.                         uint32_t op;
  185.                         bool is_mul;
  186.                 } translate[] = {
  187. #define A(name) [QOP_##name] = {QPU_A_##name, false}
  188. #define M(name) [QOP_##name] = {QPU_M_##name, true}
  189.                         A(FADD),
  190.                         A(FSUB),
  191.                         A(FMIN),
  192.                         A(FMAX),
  193.                         A(FMINABS),
  194.                         A(FMAXABS),
  195.                         A(FTOI),
  196.                         A(ITOF),
  197.                         A(ADD),
  198.                         A(SUB),
  199.                         A(SHL),
  200.                         A(SHR),
  201.                         A(ASR),
  202.                         A(MIN),
  203.                         A(MAX),
  204.                         A(AND),
  205.                         A(OR),
  206.                         A(XOR),
  207.                         A(NOT),
  208.  
  209.                         M(FMUL),
  210.                         M(MUL24),
  211.                 };
  212.  
  213.                 struct qpu_reg src[4];
  214.                 for (int i = 0; i < qir_get_op_nsrc(qinst->op); i++) {
  215.                         int index = qinst->src[i].index;
  216.                         switch (qinst->src[i].file) {
  217.                         case QFILE_NULL:
  218.                                 src[i] = qpu_rn(0);
  219.                                 break;
  220.                         case QFILE_TEMP:
  221.                                 src[i] = temp_registers[index];
  222.                                 break;
  223.                         case QFILE_UNIF:
  224.                                 src[i] = qpu_unif();
  225.                                 break;
  226.                         case QFILE_VARY:
  227.                                 src[i] = qpu_vary();
  228.                                 break;
  229.                         case QFILE_SMALL_IMM:
  230.                                 src[i].mux = QPU_MUX_SMALL_IMM;
  231.                                 src[i].addr = qpu_encode_small_immediate(qinst->src[i].index);
  232.                                 /* This should only have returned a valid
  233.                                  * small immediate field, not ~0 for failure.
  234.                                  */
  235.                                 assert(src[i].addr <= 47);
  236.                                 break;
  237.                         case QFILE_VPM:
  238.                                 assert((int)qinst->src[i].index >=
  239.                                        last_vpm_read_index);
  240.                                 last_vpm_read_index = qinst->src[i].index;
  241.                                 src[i] = qpu_ra(QPU_R_VPM);
  242.                                 break;
  243.                         }
  244.                 }
  245.  
  246.                 struct qpu_reg dst;
  247.                 switch (qinst->dst.file) {
  248.                 case QFILE_NULL:
  249.                         dst = qpu_ra(QPU_W_NOP);
  250.                         break;
  251.                 case QFILE_TEMP:
  252.                         dst = temp_registers[qinst->dst.index];
  253.                         break;
  254.                 case QFILE_VPM:
  255.                         dst = qpu_ra(QPU_W_VPM);
  256.                         break;
  257.                 case QFILE_VARY:
  258.                 case QFILE_UNIF:
  259.                 case QFILE_SMALL_IMM:
  260.                         assert(!"not reached");
  261.                         break;
  262.                 }
  263.  
  264.                 switch (qinst->op) {
  265.                 case QOP_MOV:
  266.                         /* Skip emitting the MOV if it's a no-op. */
  267.                         if (dst.mux == QPU_MUX_A || dst.mux == QPU_MUX_B ||
  268.                             dst.mux != src[0].mux || dst.addr != src[0].addr) {
  269.                                 queue(c, qpu_a_MOV(dst, src[0]));
  270.                         }
  271.                         break;
  272.  
  273.                 case QOP_SEL_X_0_ZS:
  274.                 case QOP_SEL_X_0_ZC:
  275.                 case QOP_SEL_X_0_NS:
  276.                 case QOP_SEL_X_0_NC:
  277.                         queue(c, qpu_a_MOV(dst, src[0]));
  278.                         set_last_cond_add(c, qinst->op - QOP_SEL_X_0_ZS +
  279.                                           QPU_COND_ZS);
  280.  
  281.                         queue(c, qpu_a_XOR(dst, qpu_r0(), qpu_r0()));
  282.                         set_last_cond_add(c, ((qinst->op - QOP_SEL_X_0_ZS) ^
  283.                                               1) + QPU_COND_ZS);
  284.                         break;
  285.  
  286.                 case QOP_SEL_X_Y_ZS:
  287.                 case QOP_SEL_X_Y_ZC:
  288.                 case QOP_SEL_X_Y_NS:
  289.                 case QOP_SEL_X_Y_NC:
  290.                         queue(c, qpu_a_MOV(dst, src[0]));
  291.                         set_last_cond_add(c, qinst->op - QOP_SEL_X_Y_ZS +
  292.                                           QPU_COND_ZS);
  293.  
  294.                         queue(c, qpu_a_MOV(dst, src[1]));
  295.                         set_last_cond_add(c, ((qinst->op - QOP_SEL_X_Y_ZS) ^
  296.                                               1) + QPU_COND_ZS);
  297.  
  298.                         break;
  299.  
  300.                 case QOP_RCP:
  301.                 case QOP_RSQ:
  302.                 case QOP_EXP2:
  303.                 case QOP_LOG2:
  304.                         switch (qinst->op) {
  305.                         case QOP_RCP:
  306.                                 queue(c, qpu_a_MOV(qpu_rb(QPU_W_SFU_RECIP),
  307.                                                    src[0]));
  308.                                 break;
  309.                         case QOP_RSQ:
  310.                                 queue(c, qpu_a_MOV(qpu_rb(QPU_W_SFU_RECIPSQRT),
  311.                                                    src[0]));
  312.                                 break;
  313.                         case QOP_EXP2:
  314.                                 queue(c, qpu_a_MOV(qpu_rb(QPU_W_SFU_EXP),
  315.                                                    src[0]));
  316.                                 break;
  317.                         case QOP_LOG2:
  318.                                 queue(c, qpu_a_MOV(qpu_rb(QPU_W_SFU_LOG),
  319.                                                    src[0]));
  320.                                 break;
  321.                         default:
  322.                                 abort();
  323.                         }
  324.  
  325.                         queue(c, qpu_a_MOV(dst, qpu_r4()));
  326.  
  327.                         break;
  328.  
  329.                 case QOP_PACK_8888_F:
  330.                         queue(c, qpu_m_MOV(dst, src[0]));
  331.                         *last_inst(c) |= QPU_PM;
  332.                         *last_inst(c) |= QPU_SET_FIELD(QPU_PACK_MUL_8888,
  333.                                                        QPU_PACK);
  334.                         break;
  335.  
  336.                 case QOP_PACK_8A_F:
  337.                 case QOP_PACK_8B_F:
  338.                 case QOP_PACK_8C_F:
  339.                 case QOP_PACK_8D_F:
  340.                         /* If dst doesn't happen to already contain src[0],
  341.                          * then we have to move it in.
  342.                          */
  343.                         if (qinst->src[0].file != QFILE_NULL &&
  344.                             (src[0].mux != dst.mux || src[0].addr != dst.addr)) {
  345.                                 /* Don't overwrite src1 while setting up
  346.                                  * the dst!
  347.                                  */
  348.                                 if (dst.mux == src[1].mux &&
  349.                                     dst.addr == src[1].addr) {
  350.                                         queue(c, qpu_m_MOV(qpu_rb(31), src[1]));
  351.                                         src[1] = qpu_rb(31);
  352.                                 }
  353.  
  354.                                 queue(c, qpu_m_MOV(dst, src[0]));
  355.                         }
  356.  
  357.                         queue(c, qpu_m_MOV(dst, src[1]));
  358.                         *last_inst(c) |= QPU_PM;
  359.                         *last_inst(c) |= QPU_SET_FIELD(QPU_PACK_MUL_8A +
  360.                                                        qinst->op - QOP_PACK_8A_F,
  361.                                                        QPU_PACK);
  362.                         break;
  363.  
  364.                 case QOP_FRAG_X:
  365.                         queue(c, qpu_a_ITOF(dst,
  366.                                             qpu_ra(QPU_R_XY_PIXEL_COORD)));
  367.                         break;
  368.  
  369.                 case QOP_FRAG_Y:
  370.                         queue(c, qpu_a_ITOF(dst,
  371.                                             qpu_rb(QPU_R_XY_PIXEL_COORD)));
  372.                         break;
  373.  
  374.                 case QOP_FRAG_REV_FLAG:
  375.                         queue(c, qpu_a_ITOF(dst,
  376.                                             qpu_rb(QPU_R_MS_REV_FLAGS)));
  377.                         break;
  378.  
  379.                 case QOP_FRAG_Z:
  380.                 case QOP_FRAG_W:
  381.                         /* QOP_FRAG_Z/W don't emit instructions, just allocate
  382.                          * the register to the Z/W payload.
  383.                          */
  384.                         break;
  385.  
  386.                 case QOP_TLB_DISCARD_SETUP:
  387.                         discard = true;
  388.                         queue(c, qpu_a_MOV(src[0], src[0]));
  389.                         *last_inst(c) |= QPU_SF;
  390.                         break;
  391.  
  392.                 case QOP_TLB_STENCIL_SETUP:
  393.                         queue(c, qpu_a_MOV(qpu_ra(QPU_W_TLB_STENCIL_SETUP), src[0]));
  394.                         break;
  395.  
  396.                 case QOP_TLB_Z_WRITE:
  397.                         queue(c, qpu_a_MOV(qpu_ra(QPU_W_TLB_Z), src[0]));
  398.                         if (discard) {
  399.                                 set_last_cond_add(c, QPU_COND_ZS);
  400.                         }
  401.                         break;
  402.  
  403.                 case QOP_TLB_COLOR_READ:
  404.                         queue(c, qpu_NOP());
  405.                         *last_inst(c) = qpu_set_sig(*last_inst(c),
  406.                                                     QPU_SIG_COLOR_LOAD);
  407.  
  408.                         break;
  409.  
  410.                 case QOP_TLB_COLOR_WRITE:
  411.                         queue(c, qpu_a_MOV(qpu_tlbc(), src[0]));
  412.                         if (discard) {
  413.                                 set_last_cond_add(c, QPU_COND_ZS);
  414.                         }
  415.                         break;
  416.  
  417.                 case QOP_VARY_ADD_C:
  418.                         queue(c, qpu_a_FADD(dst, src[0], qpu_r5()));
  419.                         break;
  420.  
  421.                 case QOP_PACK_SCALED: {
  422.                         uint64_t a = (qpu_a_MOV(dst, src[0]) |
  423.                                       QPU_SET_FIELD(QPU_PACK_A_16A,
  424.                                                     QPU_PACK));
  425.                         uint64_t b = (qpu_a_MOV(dst, src[1]) |
  426.                                       QPU_SET_FIELD(QPU_PACK_A_16B,
  427.                                                     QPU_PACK));
  428.  
  429.                         if (dst.mux == src[1].mux && dst.addr == src[1].addr) {
  430.                                 queue(c, b);
  431.                                 queue(c, a);
  432.                         } else {
  433.                                 queue(c, a);
  434.                                 queue(c, b);
  435.                         }
  436.                         break;
  437.                 }
  438.  
  439.                 case QOP_TEX_S:
  440.                 case QOP_TEX_T:
  441.                 case QOP_TEX_R:
  442.                 case QOP_TEX_B:
  443.                         queue(c, qpu_a_MOV(qpu_rb(QPU_W_TMU0_S +
  444.                                                   (qinst->op - QOP_TEX_S)),
  445.                                            src[0]));
  446.                         break;
  447.  
  448.                 case QOP_TEX_DIRECT:
  449.                         fixup_raddr_conflict(c, dst, &src[0], &src[1]);
  450.                         queue(c, qpu_a_ADD(qpu_rb(QPU_W_TMU0_S), src[0], src[1]));
  451.                         break;
  452.  
  453.                 case QOP_TEX_RESULT:
  454.                         queue(c, qpu_NOP());
  455.                         *last_inst(c) = qpu_set_sig(*last_inst(c),
  456.                                                     QPU_SIG_LOAD_TMU0);
  457.  
  458.                         break;
  459.  
  460.                 case QOP_R4_UNPACK_A:
  461.                 case QOP_R4_UNPACK_B:
  462.                 case QOP_R4_UNPACK_C:
  463.                 case QOP_R4_UNPACK_D:
  464.                         assert(src[0].mux == QPU_MUX_R4);
  465.                         queue(c, qpu_a_MOV(dst, src[0]));
  466.                         *last_inst(c) |= QPU_PM;
  467.                         *last_inst(c) |= QPU_SET_FIELD(QPU_UNPACK_8A +
  468.                                                        (qinst->op -
  469.                                                         QOP_R4_UNPACK_A),
  470.                                                        QPU_UNPACK);
  471.  
  472.                         break;
  473.  
  474.                 case QOP_UNPACK_8A_F:
  475.                 case QOP_UNPACK_8B_F:
  476.                 case QOP_UNPACK_8C_F:
  477.                 case QOP_UNPACK_8D_F:
  478.                 case QOP_UNPACK_16A_F:
  479.                 case QOP_UNPACK_16B_F: {
  480.                         assert(src[0].mux == QPU_MUX_A);
  481.  
  482.                         /* Since we're setting the pack bits, if the
  483.                          * destination is in A it would get re-packed.
  484.                          */
  485.                         queue(c, qpu_a_FMAX((dst.mux == QPU_MUX_A ?
  486.                                              qpu_rb(31) : dst),
  487.                                             src[0], src[0]));
  488.                         *last_inst(c) |= QPU_SET_FIELD(unpack_map[qinst->op -
  489.                                                                   QOP_UNPACK_8A_F],
  490.                                                        QPU_UNPACK);
  491.  
  492.                         if (dst.mux == QPU_MUX_A) {
  493.                                 queue(c, qpu_a_MOV(dst, qpu_rb(31)));
  494.                         }
  495.                 }
  496.                         break;
  497.  
  498.                 case QOP_UNPACK_8A_I:
  499.                 case QOP_UNPACK_8B_I:
  500.                 case QOP_UNPACK_8C_I:
  501.                 case QOP_UNPACK_8D_I:
  502.                 case QOP_UNPACK_16A_I:
  503.                 case QOP_UNPACK_16B_I: {
  504.                         assert(src[0].mux == QPU_MUX_A);
  505.  
  506.                         /* Since we're setting the pack bits, if the
  507.                          * destination is in A it would get re-packed.
  508.                          */
  509.                         queue(c, qpu_a_MOV((dst.mux == QPU_MUX_A ?
  510.                                             qpu_rb(31) : dst), src[0]));
  511.                         *last_inst(c) |= QPU_SET_FIELD(unpack_map[qinst->op -
  512.                                                                   QOP_UNPACK_8A_I],
  513.                                                        QPU_UNPACK);
  514.  
  515.                         if (dst.mux == QPU_MUX_A) {
  516.                                 queue(c, qpu_a_MOV(dst, qpu_rb(31)));
  517.                         }
  518.                 }
  519.                         break;
  520.  
  521.                 default:
  522.                         assert(qinst->op < ARRAY_SIZE(translate));
  523.                         assert(translate[qinst->op].op != 0); /* NOPs */
  524.  
  525.                         /* If we have only one source, put it in the second
  526.                          * argument slot as well so that we don't take up
  527.                          * another raddr just to get unused data.
  528.                          */
  529.                         if (qir_get_op_nsrc(qinst->op) == 1)
  530.                                 src[1] = src[0];
  531.  
  532.                         fixup_raddr_conflict(c, dst, &src[0], &src[1]);
  533.  
  534.                         if (translate[qinst->op].is_mul) {
  535.                                 queue(c, qpu_m_alu2(translate[qinst->op].op,
  536.                                                     dst,
  537.                                                     src[0], src[1]));
  538.                         } else {
  539.                                 queue(c, qpu_a_alu2(translate[qinst->op].op,
  540.                                                     dst,
  541.                                                     src[0], src[1]));
  542.                         }
  543.  
  544.                         break;
  545.                 }
  546.  
  547.                 if (qinst->sf) {
  548.                         assert(!qir_is_multi_instruction(qinst));
  549.                         *last_inst(c) |= QPU_SF;
  550.                 }
  551.         }
  552.  
  553.         qpu_schedule_instructions(c);
  554.  
  555.         /* thread end can't have VPM write or read */
  556.         if (QPU_GET_FIELD(c->qpu_insts[c->qpu_inst_count - 1],
  557.                           QPU_WADDR_ADD) == QPU_W_VPM ||
  558.             QPU_GET_FIELD(c->qpu_insts[c->qpu_inst_count - 1],
  559.                           QPU_WADDR_MUL) == QPU_W_VPM ||
  560.             QPU_GET_FIELD(c->qpu_insts[c->qpu_inst_count - 1],
  561.                           QPU_RADDR_A) == QPU_R_VPM ||
  562.             QPU_GET_FIELD(c->qpu_insts[c->qpu_inst_count - 1],
  563.                           QPU_RADDR_B) == QPU_R_VPM) {
  564.                 qpu_serialize_one_inst(c, qpu_NOP());
  565.         }
  566.  
  567.         /* thread end can't have uniform read */
  568.         if (QPU_GET_FIELD(c->qpu_insts[c->qpu_inst_count - 1],
  569.                           QPU_RADDR_A) == QPU_R_UNIF ||
  570.             QPU_GET_FIELD(c->qpu_insts[c->qpu_inst_count - 1],
  571.                           QPU_RADDR_B) == QPU_R_UNIF) {
  572.                 qpu_serialize_one_inst(c, qpu_NOP());
  573.         }
  574.  
  575.         /* thread end can't have TLB operations */
  576.         if (qpu_inst_is_tlb(c->qpu_insts[c->qpu_inst_count - 1]))
  577.                 qpu_serialize_one_inst(c, qpu_NOP());
  578.  
  579.         c->qpu_insts[c->qpu_inst_count - 1] =
  580.                 qpu_set_sig(c->qpu_insts[c->qpu_inst_count - 1],
  581.                             QPU_SIG_PROG_END);
  582.         qpu_serialize_one_inst(c, qpu_NOP());
  583.         qpu_serialize_one_inst(c, qpu_NOP());
  584.  
  585.         switch (c->stage) {
  586.         case QSTAGE_VERT:
  587.         case QSTAGE_COORD:
  588.                 break;
  589.         case QSTAGE_FRAG:
  590.                 c->qpu_insts[c->qpu_inst_count - 1] =
  591.                         qpu_set_sig(c->qpu_insts[c->qpu_inst_count - 1],
  592.                                     QPU_SIG_SCOREBOARD_UNLOCK);
  593.                 break;
  594.         }
  595.  
  596.         if (vc4_debug & VC4_DEBUG_QPU)
  597.                 vc4_dump_program(c);
  598.  
  599.         vc4_qpu_validate(c->qpu_insts, c->qpu_inst_count);
  600.  
  601.         free(temp_registers);
  602. }
  603.