X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fvc4%2Fvc4_qir_lower_uniforms.c;h=d7c22e75c2938fc52513fb64c8deb9a7627d7a60;hb=edb04953c8b8520108f333b1e289f18719a7d597;hp=63f5eb2285829d1ce8bd1a1e16f5443d205081b4;hpb=85316d059c899ac096331251de6b233229aa0b4f;p=mesa.git diff --git a/src/gallium/drivers/vc4/vc4_qir_lower_uniforms.c b/src/gallium/drivers/vc4/vc4_qir_lower_uniforms.c index 63f5eb22858..d7c22e75c29 100644 --- a/src/gallium/drivers/vc4/vc4_qir_lower_uniforms.c +++ b/src/gallium/drivers/vc4/vc4_qir_lower_uniforms.c @@ -22,14 +22,10 @@ */ /** - * @file vc4_opt_algebraic.c + * @file vc4_qir_lower_uniforms.c * - * This is the optimization pass for miscellaneous changes to instructions - * where we can simplify the operation by some knowledge about the specific - * operations. - * - * Mostly this will be a matter of turning things into MOVs so that they can - * later be copy-propagated out. + * This is the pre-code-generation pass for fixing up instructions that try to + * read from multiple uniform values. */ #include "vc4_qir.h" @@ -52,7 +48,7 @@ static void add_uniform(struct hash_table *ht, struct qreg reg) { struct hash_entry *entry; - void *key = (void *)(uintptr_t)reg.index; + void *key = (void *)(uintptr_t)(reg.index + 1); entry = _mesa_hash_table_search(ht, key); if (entry) { @@ -66,11 +62,11 @@ static void remove_uniform(struct hash_table *ht, struct qreg reg) { struct hash_entry *entry; - void *key = (void *)(uintptr_t)reg.index; + void *key = (void *)(uintptr_t)(reg.index + 1); entry = _mesa_hash_table_search(ht, key); assert(entry); - entry->data--; + entry->data = (void *)(((uintptr_t) entry->data) - 1); if (entry->data == NULL) _mesa_hash_table_remove(ht, entry); } @@ -81,14 +77,40 @@ is_lowerable_uniform(struct qinst *inst, int i) if (inst->src[i].file != QFILE_UNIF) return false; if (qir_is_tex(inst)) - return i != 1; + return i != qir_get_tex_uniform_src(inst); return true; } +/* Returns the number of different uniform values referenced by the + * instruction. + */ +static uint32_t +qir_get_instruction_uniform_count(struct qinst *inst) +{ + uint32_t count = 0; + + for (int i = 0; i < qir_get_nsrc(inst); i++) { + if (inst->src[i].file != QFILE_UNIF) + continue; + + bool is_duplicate = false; + for (int j = 0; j < i; j++) { + if (inst->src[j].file == QFILE_UNIF && + inst->src[j].index == inst->src[i].index) { + is_duplicate = true; + break; + } + } + if (!is_duplicate) + count++; + } + + return count; +} + void qir_lower_uniforms(struct vc4_compile *c) { - struct simple_node *node; struct hash_table *ht = _mesa_hash_table_create(c, index_hash, index_compare); @@ -96,17 +118,10 @@ qir_lower_uniforms(struct vc4_compile *c) * than one uniform referenced, and add those uniform values to the * ht. */ - foreach(node, &c->instructions) { - struct qinst *inst = (struct qinst *)node; - uint32_t nsrc = qir_get_op_nsrc(inst->op); + qir_for_each_inst_inorder(inst, c) { + uint32_t nsrc = qir_get_nsrc(inst); - uint32_t count = 0; - for (int i = 0; i < nsrc; i++) { - if (inst->src[i].file == QFILE_UNIF) - count++; - } - - if (count <= 1) + if (qir_get_instruction_uniform_count(inst) <= 1) continue; for (int i = 0; i < nsrc; i++) { @@ -121,53 +136,65 @@ qir_lower_uniforms(struct vc4_compile *c) */ uint32_t max_count = 0; uint32_t max_index = 0; - struct hash_entry *entry; hash_table_foreach(ht, entry) { uint32_t count = (uintptr_t)entry->data; - uint32_t index = (uintptr_t)entry->key; + uint32_t index = (uintptr_t)entry->key - 1; if (count > max_count) { max_count = count; max_index = index; } } + struct qreg unif = qir_reg(QFILE_UNIF, max_index); + /* Now, find the instructions using this uniform and make them * reference a temp instead. */ - struct qreg temp = qir_get_temp(c); - struct qreg unif = { QFILE_UNIF, max_index }; - struct qinst *mov = qir_inst(QOP_MOV, temp, unif, c->undef); - insert_at_head(&c->instructions, &mov->link); - c->defs[temp.index] = mov; - foreach(node, &c->instructions) { - struct qinst *inst = (struct qinst *)node; - uint32_t nsrc = qir_get_op_nsrc(inst->op); - - uint32_t count = 0; - for (int i = 0; i < nsrc; i++) { - if (inst->src[i].file == QFILE_UNIF) - count++; - } - - if (count <= 1) - continue; - - for (int i = 0; i < nsrc; i++) { - if (is_lowerable_uniform(inst, i) && - inst->src[i].index == max_index) { - inst->src[i] = temp; - remove_uniform(ht, unif); - count--; + qir_for_each_block(block, c) { + struct qinst *mov = NULL; + + qir_for_each_inst(inst, block) { + uint32_t nsrc = qir_get_nsrc(inst); + + uint32_t count = qir_get_instruction_uniform_count(inst); + + if (count <= 1) + continue; + + /* If the block doesn't have a load of hte + * uniform yet, add it. We could potentially + * do better and CSE MOVs from multiple blocks + * into dominating blocks, except that may + * cause troubles for register allocation. + */ + if (!mov) { + mov = qir_inst(QOP_MOV, qir_get_temp(c), + unif, c->undef); + list_add(&mov->link, + &block->instructions); + c->defs[mov->dst.index] = mov; } - } - /* If the instruction doesn't need lowering any more, - * then drop it from the list. - */ - if (count <= 1) { + bool removed = false; for (int i = 0; i < nsrc; i++) { - if (is_lowerable_uniform(inst, i)) - remove_uniform(ht, inst->src[i]); + if (is_lowerable_uniform(inst, i) && + inst->src[i].index == max_index) { + inst->src[i] = mov->dst; + remove_uniform(ht, unif); + removed = true; + } + } + if (removed) + count--; + + /* If the instruction doesn't need lowering any more, + * then drop it from the list. + */ + if (count <= 1) { + for (int i = 0; i < nsrc; i++) { + if (is_lowerable_uniform(inst, i)) + remove_uniform(ht, inst->src[i]); + } } } }