Ejemplo n.º 1
0
static bool
qir_opt_peephole_sf_block(struct vc4_compile *c, struct qblock *block)
{
        bool progress = false;
        /* We don't have liveness dataflow analysis for flags, but we also
         * never generate a use of flags across control flow, so just treat
         * them as unused at block exit.
         */
        bool sf_live = false;
        struct qinst *last_sf = NULL;

        /* Walk the block from bottom to top, tracking if the SF is used, and
         * removing unused or repeated ones.
         */
        qir_for_each_inst_rev(inst, block) {
                if (inst->sf) {
                        if (!sf_live) {
                                /* Our instruction's SF isn't read, so drop it.
                                 */
                                dump_from(c, inst, "dead SF");
                                inst->sf = false;
                                dump_to(c, inst);
                                progress = true;
                        } else if (last_sf &&
                                   inst_result_equals(last_sf, inst)) {
                                /* The last_sf sets up same value as inst, so
                                 * just drop the later one.
                                 */
                                dump_from(c, last_sf, "repeated SF");
                                last_sf->sf = false;
                                dump_to(c, last_sf);
                                progress = true;
                                last_sf = inst;
                        } else {
                                last_sf = inst;
                        }
                        sf_live = false;
                }

                if (last_sf) {
                        if (inst_srcs_updated(last_sf, inst))
                                last_sf = NULL;
                }

                if (qir_depends_on_flags(inst))
                        sf_live = true;
        }

        return progress;
}
Ejemplo n.º 2
0
bool
qir_opt_peephole_sf(struct vc4_compile *c)
{
        bool progress = false;
        bool sf_live = false;
        struct qinst *last_sf = NULL;

        /* Walk the block from bottom to top, tracking if the SF is used, and
         * removing unused or repeated ones.
         */
        list_for_each_entry_rev(struct qinst, inst, &c->instructions, link) {
                if (inst->sf) {
                        if (!sf_live) {
                                /* Our instruction's SF isn't read, so drop it.
                                 */
                                dump_from(c, inst, "dead SF");
                                inst->sf = false;
                                dump_to(c, inst);
                                progress = true;
                        } else if (last_sf &&
                                   inst_result_equals(last_sf, inst)) {
                                /* The last_sf sets up same value as inst, so
                                 * just drop the later one.
                                 */
                                dump_from(c, last_sf, "repeated SF");
                                last_sf->sf = false;
                                dump_to(c, last_sf);
                                progress = true;
                                last_sf = inst;
                        } else {
                                last_sf = inst;
                        }
                        sf_live = false;
                }

                if (last_sf) {
                        if (inst_srcs_updated(last_sf, inst))
                                last_sf = NULL;
                }

                if (qir_depends_on_flags(inst))
                        sf_live = true;
        }

        return progress;
}
Ejemplo n.º 3
0
static void
replace_with_mov(struct vc4_compile *c, struct qinst *inst, struct qreg arg)
{
        dump_from(c, inst);
        if (qir_is_mul(inst))
                inst->op = QOP_MMOV;
        else if (qir_is_float_input(inst))
                inst->op = QOP_FMOV;
        else
                inst->op = QOP_MOV;
        inst->src[0] = arg;
        inst->src[1] = c->undef;
        dump_to(c, inst);
}
Ejemplo n.º 4
0
static bool
constant_fold(struct vc4_compile *c, struct qinst *inst)
{
        int nsrc = qir_get_op_nsrc(inst->op);
        uint32_t ui[nsrc];

        for (int i = 0; i < nsrc; i++) {
                struct qreg reg = inst->src[i];
                if (reg.file == QFILE_UNIF &&
                    c->uniform_contents[reg.index] == QUNIFORM_CONSTANT) {
                        ui[i] = c->uniform_data[reg.index];
                } else if (reg.file == QFILE_SMALL_IMM) {
                        ui[i] = reg.index;
                } else {
                        return false;
                }
        }

        uint32_t result = 0;
        switch (inst->op) {
        case QOP_SHR:
                result = ui[0] >> ui[1];
                break;

        default:
                return false;
        }

        dump_from(c, inst);

        inst->src[0] = qir_uniform_ui(c, result);
        for (int i = 1; i < nsrc; i++)
                inst->src[i] = c->undef;
        inst->op = QOP_MOV;

        dump_to(c, inst);
        return true;
}
Ejemplo n.º 5
0
bool
qir_opt_algebraic(struct vc4_compile *c)
{
        bool progress = false;

        qir_for_each_inst_inorder(inst, c) {
                switch (inst->op) {
                case QOP_FMIN:
                        if (is_1f(c, inst->src[1]) &&
                            inst->src[0].pack >= QPU_UNPACK_8D_REP &&
                            inst->src[0].pack <= QPU_UNPACK_8D) {
                                replace_with_mov(c, inst, inst->src[0]);
                                progress = true;
                        }
                        break;

                case QOP_FMAX:
                        if (is_zero(c, inst->src[1]) &&
                            inst->src[0].pack >= QPU_UNPACK_8D_REP &&
                            inst->src[0].pack <= QPU_UNPACK_8D) {
                                replace_with_mov(c, inst, inst->src[0]);
                                progress = true;
                        }
                        break;

                case QOP_FSUB:
                case QOP_SUB:
                        if (is_zero(c, inst->src[1])) {
                                replace_with_mov(c, inst, inst->src[0]);
                                progress = true;
                        }
                        break;

                case QOP_ADD:
                        if (replace_x_0_with_x(c, inst, 0) ||
                            replace_x_0_with_x(c, inst, 1)) {
                                progress = true;
                                break;
                        }
                        break;

                case QOP_FADD:
                        if (replace_x_0_with_x(c, inst, 0) ||
                            replace_x_0_with_x(c, inst, 1)) {
                                progress = true;
                                break;
                        }

                        /* FADD(a, FSUB(0, b)) -> FSUB(a, b) */
                        if (inst->src[1].file == QFILE_TEMP &&
                            c->defs[inst->src[1].index] &&
                            c->defs[inst->src[1].index]->op == QOP_FSUB) {
                                struct qinst *fsub = c->defs[inst->src[1].index];
                                if (is_zero(c, fsub->src[0])) {
                                        dump_from(c, inst);
                                        inst->op = QOP_FSUB;
                                        inst->src[1] = fsub->src[1];
                                        progress = true;
                                        dump_to(c, inst);
                                        break;
                                }
                        }

                        /* FADD(FSUB(0, b), a) -> FSUB(a, b) */
                        if (inst->src[0].file == QFILE_TEMP &&
                            c->defs[inst->src[0].index] &&
                            c->defs[inst->src[0].index]->op == QOP_FSUB) {
                                struct qinst *fsub = c->defs[inst->src[0].index];
                                if (is_zero(c, fsub->src[0])) {
                                        dump_from(c, inst);
                                        inst->op = QOP_FSUB;
                                        inst->src[0] = inst->src[1];
                                        inst->src[1] = fsub->src[1];
                                        dump_to(c, inst);
                                        progress = true;
                                        break;
                                }
                        }
                        break;

                case QOP_FMUL:
                        if (!inst->dst.pack &&
                            (replace_x_0_with_0(c, inst, 0) ||
                             replace_x_0_with_0(c, inst, 1) ||
                             fmul_replace_one(c, inst, 0) ||
                             fmul_replace_one(c, inst, 1))) {
                                progress = true;
                                break;
                        }
                        break;

                case QOP_MUL24:
                        if (!inst->dst.pack &&
                            (replace_x_0_with_0(c, inst, 0) ||
                             replace_x_0_with_0(c, inst, 1))) {
                                progress = true;
                                break;
                        }
                        break;

                case QOP_AND:
                        if (replace_x_0_with_0(c, inst, 0) ||
                            replace_x_0_with_0(c, inst, 1)) {
                                progress = true;
                                break;
                        }

                        if (is_constant_value(c, inst->src[0], ~0)) {
                                replace_with_mov(c, inst, inst->src[1]);
                                progress = true;
                                break;
                        }
                        if (is_constant_value(c, inst->src[1], ~0)) {
                                replace_with_mov(c, inst, inst->src[0]);
                                progress = true;
                                break;
                        }
                        break;

                case QOP_OR:
                        if (replace_x_0_with_x(c, inst, 0) ||
                            replace_x_0_with_x(c, inst, 1)) {
                                progress = true;
                                break;
                        }
                        break;

                case QOP_RCP:
                        if (is_1f(c, inst->src[0])) {
                                replace_with_mov(c, inst, inst->src[0]);
                                progress = true;
                                break;
                        }
                        break;

                default:
                        break;
                }
        }

        return progress;
}