Exemple #1
0
uint64_t
qpu_merge_inst(uint64_t a, uint64_t b)
{
        uint64_t merge = a | b;
        bool ok = true;
        uint32_t a_sig = QPU_GET_FIELD(a, QPU_SIG);
        uint32_t b_sig = QPU_GET_FIELD(b, QPU_SIG);

        if (QPU_GET_FIELD(a, QPU_OP_ADD) != QPU_A_NOP &&
            QPU_GET_FIELD(b, QPU_OP_ADD) != QPU_A_NOP) {
                if (QPU_GET_FIELD(a, QPU_OP_MUL) != QPU_M_NOP ||
                    QPU_GET_FIELD(b, QPU_OP_MUL) != QPU_M_NOP ||
                    !(convert_mov(&a) || convert_mov(&b))) {
                        return 0;
                } else {
                        merge = a | b;
                }
        }

        if (QPU_GET_FIELD(a, QPU_OP_MUL) != QPU_M_NOP &&
            QPU_GET_FIELD(b, QPU_OP_MUL) != QPU_M_NOP)
                return 0;

        if (qpu_num_sf_accesses(a) && qpu_num_sf_accesses(b))
                return 0;

        if (a_sig == QPU_SIG_LOAD_IMM ||
            b_sig == QPU_SIG_LOAD_IMM ||
            a_sig == QPU_SIG_SMALL_IMM ||
            b_sig == QPU_SIG_SMALL_IMM ||
            a_sig == QPU_SIG_BRANCH ||
            b_sig == QPU_SIG_BRANCH) {
                return 0;
        }

        ok = ok && merge_fields(&merge, a, b, QPU_SIG_MASK,
                                QPU_SET_FIELD(QPU_SIG_NONE, QPU_SIG));

        /* Misc fields that have to match exactly. */
        ok = ok && merge_fields(&merge, a, b, QPU_SF, ~0);

        if (!merge_fields(&merge, a, b, QPU_RADDR_A_MASK,
                          QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_A))) {
                /* Since we tend to use regfile A by default both for register
                 * allocation and for our special values (uniforms and
                 * varyings), try swapping uniforms and varyings to regfile B
                 * to resolve raddr A conflicts.
                 */
                if (!try_swap_ra_file(&merge, &a, &b) &&
                    !try_swap_ra_file(&merge, &b, &a)) {
                        return 0;
                }
        }

        ok = ok && merge_fields(&merge, a, b, QPU_RADDR_B_MASK,
                                QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_B));

        ok = ok && merge_fields(&merge, a, b, QPU_WADDR_ADD_MASK,
                                QPU_SET_FIELD(QPU_W_NOP, QPU_WADDR_ADD));
        ok = ok && merge_fields(&merge, a, b, QPU_WADDR_MUL_MASK,
                                QPU_SET_FIELD(QPU_W_NOP, QPU_WADDR_MUL));

        /* Allow disagreement on WS (swapping A vs B physical reg file as the
         * destination for ADD/MUL) if one of the original instructions
         * ignores it (probably because it's just writing to accumulators).
         */
        if (qpu_waddr_ignores_ws(QPU_GET_FIELD(a, QPU_WADDR_ADD)) &&
            qpu_waddr_ignores_ws(QPU_GET_FIELD(a, QPU_WADDR_MUL))) {
                merge = (merge & ~QPU_WS) | (b & QPU_WS);
        } else if (qpu_waddr_ignores_ws(QPU_GET_FIELD(b, QPU_WADDR_ADD)) &&
                   qpu_waddr_ignores_ws(QPU_GET_FIELD(b, QPU_WADDR_MUL))) {
                merge = (merge & ~QPU_WS) | (a & QPU_WS);
        } else {
                if ((a & QPU_WS) != (b & QPU_WS))
                        return 0;
        }

        if (!merge_fields(&merge, a, b, QPU_PM, ~0)) {
                /* If one instruction has PM bit set and the other not, the
                 * one without PM shouldn't do packing/unpacking, and we
                 * have to make sure non-NOP packing/unpacking from PM
                 * instruction aren't added to it.
                 */
                uint64_t temp;

                /* Let a be the one with PM bit */
                if (!(a & QPU_PM)) {
                        temp = a;
                        a = b;
                        b = temp;
                }

                if ((b & (QPU_PACK_MASK | QPU_UNPACK_MASK)) != 0)
                        return 0;

                if ((a & QPU_PACK_MASK) != 0 &&
                    QPU_GET_FIELD(b, QPU_OP_MUL) != QPU_M_NOP)
                        return 0;

                if ((a & QPU_UNPACK_MASK) != 0 && reads_r4(b))
                        return 0;
        } else {
                /* packing: Make sure that non-NOP packs agree, then deal with
                 * special-case failing of adding a non-NOP pack to something
                 * with a NOP pack.
                 */
                if (!merge_fields(&merge, a, b, QPU_PACK_MASK, 0))
                        return 0;
                bool new_a_pack = (QPU_GET_FIELD(a, QPU_PACK) !=
                                QPU_GET_FIELD(merge, QPU_PACK));
                bool new_b_pack = (QPU_GET_FIELD(b, QPU_PACK) !=
                                QPU_GET_FIELD(merge, QPU_PACK));
                if (!(merge & QPU_PM)) {
                        /* Make sure we're not going to be putting a new
                         * a-file packing on either half.
                         */
                        if (new_a_pack && writes_a_file(a))
                                return 0;

                        if (new_b_pack && writes_a_file(b))
                                return 0;
                } else {
                        /* Make sure we're not going to be putting new MUL
                         * packing oneither half.
                         */
                        if (new_a_pack &&
                            QPU_GET_FIELD(a, QPU_OP_MUL) != QPU_M_NOP)
                                return 0;

                        if (new_b_pack &&
                            QPU_GET_FIELD(b, QPU_OP_MUL) != QPU_M_NOP)
                                return 0;
                }

                /* unpacking: Make sure that non-NOP unpacks agree, then deal
                 * with special-case failing of adding a non-NOP unpack to
                 * something with a NOP unpack.
                 */
                if (!merge_fields(&merge, a, b, QPU_UNPACK_MASK, 0))
                        return 0;
                bool new_a_unpack = (QPU_GET_FIELD(a, QPU_UNPACK) !=
                                QPU_GET_FIELD(merge, QPU_UNPACK));
                bool new_b_unpack = (QPU_GET_FIELD(b, QPU_UNPACK) !=
                                QPU_GET_FIELD(merge, QPU_UNPACK));
                if (!(merge & QPU_PM)) {
                        /* Make sure we're not going to be putting a new
                         * a-file packing on either half.
                         */
                        if (new_a_unpack &&
                            QPU_GET_FIELD(a, QPU_RADDR_A) != QPU_R_NOP)
                                return 0;

                        if (new_b_unpack &&
                            QPU_GET_FIELD(b, QPU_RADDR_A) != QPU_R_NOP)
                                return 0;
                } else {
                        /* Make sure we're not going to be putting new r4
                         * unpack on either half.
                         */
                        if (new_a_unpack && reads_r4(a))
                                return 0;

                        if (new_b_unpack && reads_r4(b))
                                return 0;
                }
        }

        if (ok)
                return merge;
        else
                return 0;
}
Exemple #2
0
void ROW::operator+=(const ROW& b)
{
    prepare_field((b.value_number + value_number));//orig pole bude volne k zapisu
    merge_fields(b.values, val[na], b.index, in[na], b.value_number, value_number, values, index, value_number);
}