diff --git a/src/gallium/drivers/vc4/vc4_opt_copy_propagation.c b/src/gallium/drivers/vc4/vc4_opt_copy_propagation.c index a180f040b54..f8f1365f658 100644 --- a/src/gallium/drivers/vc4/vc4_opt_copy_propagation.c +++ b/src/gallium/drivers/vc4/vc4_opt_copy_propagation.c @@ -34,85 +34,160 @@ #include "vc4_qir.h" +static bool +is_copy_mov(struct qinst *inst) +{ + if (!inst) + return false; + + if (inst->op != QOP_MOV && + inst->op != QOP_FMOV && + inst->op != QOP_MMOV) { + return false; + } + + if (inst->dst.file != QFILE_TEMP) + return false; + + if (inst->src[0].file != QFILE_TEMP && + inst->src[0].file != QFILE_UNIF) { + return false; + } + + if (inst->dst.pack || inst->cond != QPU_COND_ALWAYS) + return false; + + return true; + +} + +static bool +try_copy_prop(struct vc4_compile *c, struct qinst *inst, struct qinst **movs) +{ + bool debug = false; + bool progress = false; + + for (int i = 0; i < qir_get_op_nsrc(inst->op); i++) { + if (inst->src[i].file != QFILE_TEMP) + continue; + + /* We have two ways of finding MOVs we can copy propagate + * from. One is if it's an SSA def: then we can reuse it from + * any block in the program, as long as its source is also an + * SSA def. Alternatively, if it's in the "movs" array + * tracked within the block, then we know the sources for it + * haven't been changed since we saw the instruction within + * our block. + */ + struct qinst *mov = movs[inst->src[i].index]; + if (!mov) { + if (!is_copy_mov(c->defs[inst->src[i].index])) + continue; + mov = c->defs[inst->src[i].index]; + + if (mov->src[0].file == QFILE_TEMP && + !c->defs[mov->src[0].index]) + continue; + } + + uint8_t unpack; + if (mov->src[0].pack) { + /* Make sure that the meaning of the unpack + * would be the same between the two + * instructions. + */ + if (qir_is_float_input(inst) != + qir_is_float_input(mov)) { + continue; + } + + /* There's only one unpack field, so make sure + * this instruction doesn't already use it. + */ + bool already_has_unpack = false; + for (int j = 0; j < qir_get_op_nsrc(inst->op); j++) { + if (inst->src[j].pack) + already_has_unpack = true; + } + if (already_has_unpack) + continue; + + /* A destination pack requires the PM bit to + * be set to a specific value already, which + * may be different from ours. + */ + if (inst->dst.pack) + continue; + + unpack = mov->src[0].pack; + } else { + unpack = inst->src[i].pack; + } + + if (debug) { + fprintf(stderr, "Copy propagate: "); + qir_dump_inst(c, inst); + fprintf(stderr, "\n"); + } + + inst->src[i] = mov->src[0]; + inst->src[i].pack = unpack; + + if (debug) { + fprintf(stderr, "to: "); + qir_dump_inst(c, inst); + fprintf(stderr, "\n"); + } + + progress = true; + } + + return progress; +} + +static void +apply_kills(struct vc4_compile *c, struct qinst **movs, struct qinst *inst) +{ + if (inst->dst.file != QFILE_TEMP) + return; + + for (int i = 0; i < c->num_temps; i++) { + if (movs[i] && + (movs[i]->dst.index == inst->dst.index || + (movs[i]->src[0].file == QFILE_TEMP && + movs[i]->src[0].index == inst->dst.index))) { + movs[i] = NULL; + } + } +} + bool qir_opt_copy_propagation(struct vc4_compile *c) { bool progress = false; - bool debug = false; + struct qinst **movs; - qir_for_each_inst_inorder(inst, c) { - int nsrc = qir_get_op_nsrc(inst->op); - for (int i = 0; i < nsrc; i++) { - if (inst->src[i].file != QFILE_TEMP) - continue; + movs = ralloc_array(c, struct qinst *, c->num_temps); + if (!movs) + return false; - struct qinst *mov = c->defs[inst->src[i].index]; - if (!mov || - (mov->op != QOP_MOV && - mov->op != QOP_FMOV && - mov->op != QOP_MMOV)) { - continue; - } + qir_for_each_block(block, c) { + /* The MOVs array tracks only available movs within the + * block. + */ + memset(movs, 0, sizeof(struct qinst *) * c->num_temps); - if (mov->src[0].file != QFILE_TEMP && - mov->src[0].file != QFILE_UNIF) { - continue; - } + qir_for_each_inst(inst, block) { + progress = try_copy_prop(c, inst, movs) || progress; - if (mov->dst.pack) - continue; + apply_kills(c, movs, inst); - uint8_t unpack; - if (mov->src[0].pack) { - /* Make sure that the meaning of the unpack - * would be the same between the two - * instructions. - */ - if (qir_is_float_input(inst) != - qir_is_float_input(mov)) { - continue; - } - - /* There's only one unpack field, so make sure - * this instruction doesn't already use it. - */ - bool already_has_unpack = false; - for (int j = 0; j < nsrc; j++) { - if (inst->src[j].pack) - already_has_unpack = true; - } - if (already_has_unpack) - continue; - - /* A destination pack requires the PM bit to - * be set to a specific value already, which - * may be different from ours. - */ - if (inst->dst.pack) - continue; - - unpack = mov->src[0].pack; - } else { - unpack = inst->src[i].pack; - } - - if (debug) { - fprintf(stderr, "Copy propagate: "); - qir_dump_inst(c, inst); - fprintf(stderr, "\n"); - } - - inst->src[i] = mov->src[0]; - inst->src[i].pack = unpack; - - if (debug) { - fprintf(stderr, "to: "); - qir_dump_inst(c, inst); - fprintf(stderr, "\n"); - } - - progress = true; + if (is_copy_mov(inst)) + movs[inst->dst.index] = inst; } } + + ralloc_free(movs); + return progress; }