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. /**
  25.  * @file vc4_opt_algebraic.c
  26.  *
  27.  * This is the optimization pass for miscellaneous changes to instructions
  28.  * where we can simplify the operation by some knowledge about the specific
  29.  * operations.
  30.  *
  31.  * Mostly this will be a matter of turning things into MOVs so that they can
  32.  * later be copy-propagated out.
  33.  */
  34.  
  35. #include "vc4_qir.h"
  36. #include "util/u_math.h"
  37.  
  38. static bool debug;
  39.  
  40. static void
  41. dump_from(struct vc4_compile *c, struct qinst *inst)
  42. {
  43.         if (!debug)
  44.                 return;
  45.  
  46.         fprintf(stderr, "optimizing: ");
  47.         qir_dump_inst(c, inst);
  48.         fprintf(stderr, "\n");
  49. }
  50.  
  51. static void
  52. dump_to(struct vc4_compile *c, struct qinst *inst)
  53. {
  54.         if (!debug)
  55.                 return;
  56.  
  57.         fprintf(stderr, "to: ");
  58.         qir_dump_inst(c, inst);
  59.         fprintf(stderr, "\n");
  60. }
  61.  
  62. static bool
  63. is_constant_value(struct vc4_compile *c, struct qreg reg,
  64.                   uint32_t val)
  65. {
  66.         if (reg.file == QFILE_UNIF &&
  67.             c->uniform_contents[reg.index] == QUNIFORM_CONSTANT &&
  68.             c->uniform_data[reg.index] == val) {
  69.                 return true;
  70.         }
  71.  
  72.         if (reg.file == QFILE_SMALL_IMM && reg.index == val)
  73.                 return true;
  74.  
  75.         return false;
  76. }
  77.  
  78. static bool
  79. is_zero(struct vc4_compile *c, struct qreg reg)
  80. {
  81.         reg = qir_follow_movs(c, reg);
  82.         return is_constant_value(c, reg, 0);
  83. }
  84.  
  85. static bool
  86. is_1f(struct vc4_compile *c, struct qreg reg)
  87. {
  88.         reg = qir_follow_movs(c, reg);
  89.         return is_constant_value(c, reg, fui(1.0));
  90. }
  91.  
  92. static void
  93. replace_with_mov(struct vc4_compile *c, struct qinst *inst, struct qreg arg)
  94. {
  95.         dump_from(c, inst);
  96.         inst->op = QOP_MOV;
  97.         inst->src[0] = arg;
  98.         inst->src[1] = c->undef;
  99.         dump_to(c, inst);
  100. }
  101.  
  102. static bool
  103. replace_x_0_with_x(struct vc4_compile *c,
  104.                  struct qinst *inst,
  105.                  int arg)
  106. {
  107.         if (!is_zero(c, inst->src[arg]))
  108.                 return false;
  109.         replace_with_mov(c, inst, inst->src[1 - arg]);
  110.         return true;
  111. }
  112.  
  113. static bool
  114. replace_x_0_with_0(struct vc4_compile *c,
  115.                   struct qinst *inst,
  116.                   int arg)
  117. {
  118.         if (!is_zero(c, inst->src[arg]))
  119.                 return false;
  120.         replace_with_mov(c, inst, inst->src[arg]);
  121.         return true;
  122. }
  123.  
  124. static bool
  125. fmul_replace_one(struct vc4_compile *c,
  126.                  struct qinst *inst,
  127.                  int arg)
  128. {
  129.         if (!is_1f(c, inst->src[arg]))
  130.                 return false;
  131.         replace_with_mov(c, inst, inst->src[1 - arg]);
  132.         return true;
  133. }
  134.  
  135. bool
  136. qir_opt_algebraic(struct vc4_compile *c)
  137. {
  138.         bool progress = false;
  139.         struct simple_node *node;
  140.  
  141.         foreach(node, &c->instructions) {
  142.                 struct qinst *inst = (struct qinst *)node;
  143.  
  144.                 switch (inst->op) {
  145.                 case QOP_SEL_X_Y_ZS:
  146.                 case QOP_SEL_X_Y_ZC:
  147.                 case QOP_SEL_X_Y_NS:
  148.                 case QOP_SEL_X_Y_NC:
  149.                         if (qir_reg_equals(inst->src[0], inst->src[1])) {
  150.                                 /* Turn "dst = (sf == x) ? a : a)" into
  151.                                  * "dst = a"
  152.                                  */
  153.                                 replace_with_mov(c, inst, inst->src[1]);
  154.                                 progress = true;
  155.                                 break;
  156.                         }
  157.  
  158.                         if (is_zero(c, inst->src[1])) {
  159.                                 /* Replace references to a 0 uniform value
  160.                                  * with the SEL_X_0 equivalent.
  161.                                  */
  162.                                 dump_from(c, inst);
  163.                                 inst->op -= (QOP_SEL_X_Y_ZS - QOP_SEL_X_0_ZS);
  164.                                 inst->src[1] = c->undef;
  165.                                 progress = true;
  166.                                 dump_to(c, inst);
  167.                                 break;
  168.                         }
  169.  
  170.                         if (is_zero(c, inst->src[0])) {
  171.                                 /* Replace references to a 0 uniform value
  172.                                  * with the SEL_X_0 equivalent, flipping the
  173.                                  * condition being evaluated since the operand
  174.                                  * order is flipped.
  175.                                  */
  176.                                 dump_from(c, inst);
  177.                                 inst->op -= QOP_SEL_X_Y_ZS;
  178.                                 inst->op ^= 1;
  179.                                 inst->op += QOP_SEL_X_0_ZS;
  180.                                 inst->src[0] = inst->src[1];
  181.                                 inst->src[1] = c->undef;
  182.                                 progress = true;
  183.                                 dump_to(c, inst);
  184.                                 break;
  185.                         }
  186.  
  187.                         break;
  188.  
  189.                 case QOP_FSUB:
  190.                 case QOP_SUB:
  191.                         if (is_zero(c, inst->src[1])) {
  192.                                 replace_with_mov(c, inst, inst->src[0]);
  193.                         }
  194.                         break;
  195.  
  196.                 case QOP_ADD:
  197.                         if (replace_x_0_with_x(c, inst, 0) ||
  198.                             replace_x_0_with_x(c, inst, 1)) {
  199.                                 progress = true;
  200.                                 break;
  201.                         }
  202.                         break;
  203.  
  204.                 case QOP_FADD:
  205.                         if (replace_x_0_with_x(c, inst, 0) ||
  206.                             replace_x_0_with_x(c, inst, 1)) {
  207.                                 progress = true;
  208.                                 break;
  209.                         }
  210.  
  211.                         /* FADD(a, FSUB(0, b)) -> FSUB(a, b) */
  212.                         if (inst->src[1].file == QFILE_TEMP &&
  213.                             c->defs[inst->src[1].index]->op == QOP_FSUB) {
  214.                                 struct qinst *fsub = c->defs[inst->src[1].index];
  215.                                 if (is_zero(c, fsub->src[0])) {
  216.                                         dump_from(c, inst);
  217.                                         inst->op = QOP_FSUB;
  218.                                         inst->src[1] = fsub->src[1];
  219.                                         progress = true;
  220.                                         dump_to(c, inst);
  221.                                         break;
  222.                                 }
  223.                         }
  224.  
  225.                         /* FADD(FSUB(0, b), a) -> FSUB(a, b) */
  226.                         if (inst->src[0].file == QFILE_TEMP &&
  227.                             c->defs[inst->src[0].index]->op == QOP_FSUB) {
  228.                                 struct qinst *fsub = c->defs[inst->src[0].index];
  229.                                 if (is_zero(c, fsub->src[0])) {
  230.                                         dump_from(c, inst);
  231.                                         inst->op = QOP_FSUB;
  232.                                         inst->src[0] = inst->src[1];
  233.                                         inst->src[1] = fsub->src[1];
  234.                                         dump_to(c, inst);
  235.                                         progress = true;
  236.                                         break;
  237.                                 }
  238.                         }
  239.                         break;
  240.  
  241.                 case QOP_FMUL:
  242.                         if (replace_x_0_with_0(c, inst, 0) ||
  243.                             replace_x_0_with_0(c, inst, 1) ||
  244.                             fmul_replace_one(c, inst, 0) ||
  245.                             fmul_replace_one(c, inst, 1)) {
  246.                                 progress = true;
  247.                                 break;
  248.                         }
  249.                         break;
  250.  
  251.                 case QOP_MUL24:
  252.                         if (replace_x_0_with_0(c, inst, 0) ||
  253.                             replace_x_0_with_0(c, inst, 1)) {
  254.                                 progress = true;
  255.                                 break;
  256.                         }
  257.                         break;
  258.  
  259.                 case QOP_AND:
  260.                         if (replace_x_0_with_0(c, inst, 0) ||
  261.                             replace_x_0_with_0(c, inst, 1)) {
  262.                                 progress = true;
  263.                                 break;
  264.                         }
  265.  
  266.                         if (is_constant_value(c, inst->src[0], ~0)) {
  267.                                 replace_with_mov(c, inst, inst->src[1]);
  268.                                 progress = true;
  269.                                 break;
  270.                         }
  271.                         if (is_constant_value(c, inst->src[1], ~0)) {
  272.                                 replace_with_mov(c, inst, inst->src[0]);
  273.                                 progress = true;
  274.                                 break;
  275.                         }
  276.                         break;
  277.  
  278.                 case QOP_OR:
  279.                         if (replace_x_0_with_x(c, inst, 0) ||
  280.                             replace_x_0_with_x(c, inst, 1)) {
  281.                                 progress = true;
  282.                                 break;
  283.                         }
  284.                         break;
  285.  
  286.                 default:
  287.                         break;
  288.                 }
  289.         }
  290.  
  291.         return progress;
  292. }
  293.