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