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; }
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); }