summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/vc4/vc4_opt_algebraic.c
diff options
context:
space:
mode:
authorEric Anholt <[email protected]>2014-09-24 21:37:12 -0700
committerEric Anholt <[email protected]>2014-09-29 11:33:34 -0700
commit3311513041b81fe4e2fcf2c0e8a363a6d292c7b1 (patch)
tree3c19e82e6f093aeea57c809e65a8c5f3b5652275 /src/gallium/drivers/vc4/vc4_opt_algebraic.c
parent730267eb23b418637c78662a77de0a93af91be35 (diff)
vc4: Turn a SEL_X_Y(x, 0) into SEL_X_0(x).
This may reduce register pressure and uniform counts. Drops a bunch of 0 uniform loads on vs-temp-array-mat4-index-col-row-wr.shader_test, which is failing to register allocate.
Diffstat (limited to 'src/gallium/drivers/vc4/vc4_opt_algebraic.c')
-rw-r--r--src/gallium/drivers/vc4/vc4_opt_algebraic.c75
1 files changed, 61 insertions, 14 deletions
diff --git a/src/gallium/drivers/vc4/vc4_opt_algebraic.c b/src/gallium/drivers/vc4/vc4_opt_algebraic.c
index df57e5de2df..868677acbde 100644
--- a/src/gallium/drivers/vc4/vc4_opt_algebraic.c
+++ b/src/gallium/drivers/vc4/vc4_opt_algebraic.c
@@ -34,39 +34,86 @@
#include "vc4_qir.h"
+static bool debug;
+
+static void
+dump_from(struct qinst *inst)
+{
+ if (!debug)
+ return;
+
+ fprintf(stderr, "optimizing: ");
+ qir_dump_inst(inst);
+ fprintf(stderr, "\n");
+}
+
+static void
+dump_to(struct qinst *inst)
+{
+ if (!debug)
+ return;
+
+ fprintf(stderr, "to: ");
+ qir_dump_inst(inst);
+ fprintf(stderr, "\n");
+}
+
+static struct qreg
+follow_movs(struct qinst **defs, struct qreg reg)
+{
+ while (reg.file == QFILE_TEMP && defs[reg.index]->op == QOP_MOV)
+ reg = defs[reg.index]->src[0];
+
+ return reg;
+}
+
+static bool
+is_zero(struct vc4_compile *c, struct qinst **defs, struct qreg reg)
+{
+ reg = follow_movs(defs, reg);
+
+ return (reg.file == QFILE_UNIF &&
+ c->uniform_contents[reg.index] == QUNIFORM_CONSTANT &&
+ c->uniform_data[reg.index] == 0);
+}
+
bool
qir_opt_algebraic(struct vc4_compile *c)
{
bool progress = false;
struct simple_node *node;
- bool debug = false;
+ struct qinst *defs[c->num_temps];
foreach(node, &c->instructions) {
struct qinst *inst = (struct qinst *)node;
+ if (inst->dst.file == QFILE_TEMP)
+ defs[inst->dst.index] = inst;
+
switch (inst->op) {
case QOP_SEL_X_Y_ZS:
case QOP_SEL_X_Y_ZC:
case QOP_SEL_X_Y_NS:
case QOP_SEL_X_Y_NC:
- /* Turn "dst = (sf == x) ? a : a)" into "dst = a" */
if (qir_reg_equals(inst->src[0], inst->src[1])) {
- if (debug) {
- fprintf(stderr, "optimizing: ");
- qir_dump_inst(inst);
- fprintf(stderr, "\n");
- }
-
+ /* Turn "dst = (sf == x) ? a : a)" into
+ * "dst = a"
+ */
+ dump_from(inst);
inst->op = QOP_MOV;
inst->src[0] = inst->src[1];
inst->src[1] = c->undef;
progress = true;
-
- if (debug) {
- fprintf(stderr, "to: ");
- qir_dump_inst(inst);
- fprintf(stderr, "\n");
- }
+ dump_to(inst);
+ } else if (is_zero(c, defs, inst->src[1])) {
+ /* Replace references to a 0 uniform value
+ * with the SEL_X_0 equivalent.
+ */
+ dump_from(inst);
+ inst->op -= (QOP_SEL_X_Y_ZS - QOP_SEL_X_0_ZS);
+ inst->src[1] = c->undef;
+ progress = true;
+ dump_to(inst);
}
break;