From e3fdd6689bae5757f4f917a6d6b77dda3a79a16a Mon Sep 17 00:00:00 2001 From: Simon Perretta Date: Wed, 8 Jan 2025 17:07:24 +0000 Subject: [PATCH] pco: experimental regalloc changes Signed-off-by: Simon Perretta Acked-by: Erik Faye-Lund Part-of: --- src/imagination/pco/pco_internal.h | 10 ++- src/imagination/pco/pco_ra.c | 111 ++++++++++++++++++++++++++-- src/imagination/pco/pco_trans_nir.c | 3 +- 3 files changed, 111 insertions(+), 13 deletions(-) diff --git a/src/imagination/pco/pco_internal.h b/src/imagination/pco/pco_internal.h index 6d1546f9635..4c7e02f7e4f 100644 --- a/src/imagination/pco/pco_internal.h +++ b/src/imagination/pco/pco_internal.h @@ -2439,10 +2439,12 @@ static inline bool pco_ref_mods_are_equal(pco_ref ref0, pco_ref ref1) * * \param[in] ref0 First reference. * \param[in] ref1 Second reference. + * \param[in] ignore_dtype Whether to ignore the datatype. * \return True if both references are the same. */ /* TODO: can this be simplified? */ -static inline bool pco_refs_are_equal(pco_ref ref0, pco_ref ref1) +static inline bool +pco_refs_are_equal(pco_ref ref0, pco_ref ref1, bool ignore_dtype) { if (ref0.type != ref1.type) return false; @@ -2466,7 +2468,7 @@ static inline bool pco_refs_are_equal(pco_ref ref0, pco_ref ref1) if (ref0.chans != ref1.chans) return false; - if (pco_ref_get_dtype(ref0) != pco_ref_get_dtype(ref1)) + if (!ignore_dtype && pco_ref_get_dtype(ref0) != pco_ref_get_dtype(ref1)) return false; if (pco_ref_get_bits(ref0) != pco_ref_get_bits(ref1)) @@ -2625,13 +2627,13 @@ static inline bool pco_igrp_dests_unset(pco_igrp *igrp) static inline pco_instr *find_parent_instr_from(pco_ref src, pco_instr *from) { pco_foreach_instr_dest_ssa (pdest, from) { - if (pco_refs_are_equal(*pdest, src)) + if (pco_refs_are_equal(*pdest, src, false)) return from; } pco_foreach_instr_in_func_from_rev (instr, from) { pco_foreach_instr_dest_ssa (pdest, instr) { - if (pco_refs_are_equal(*pdest, src)) + if (pco_refs_are_equal(*pdest, src, false)) return instr; } } diff --git a/src/imagination/pco/pco_ra.c b/src/imagination/pco/pco_ra.c index 933c3f22817..c13975b6490 100644 --- a/src/imagination/pco/pco_ra.c +++ b/src/imagination/pco/pco_ra.c @@ -58,6 +58,37 @@ static bool vec_has_repeated_ssas(pco_instr *vec) return false; } +static void pco_extend_live_range(pco_ref origin, + pco_ref current_ref, + pco_instr *current_instr, + struct hash_table_u64 *overrides, + struct live_range *live_ranges) +{ + pco_foreach_instr_in_func_from (instr, current_instr) { + pco_foreach_instr_src_ssa (psrc, instr) { + if (current_ref.val != psrc->val) + continue; + + pco_foreach_instr_dest_ssa (pdest, instr) { + struct vec_override *override = + _mesa_hash_table_u64_search(overrides, pdest->val); + + if (override) { + live_ranges[origin.val].end = + MAX2(live_ranges[origin.val].end, + live_ranges[override->ref.val].end); + break; + } + + live_ranges[origin.val].end = + MAX2(live_ranges[origin.val].end, instr->index); + } + + break; + } + } +} + /** * \brief Performs register allocation on a function. * @@ -153,6 +184,9 @@ static bool pco_ra_func(pco_func *func, } } + BITSET_WORD *comps = + rzalloc_array_size(ra_regs, sizeof(*comps), BITSET_WORDS(num_ssas)); + /* Overrides for vector component uses. */ pco_foreach_instr_in_func (instr, func) { if (instr->op != PCO_OP_COMP) @@ -162,9 +196,19 @@ static bool pco_ra_func(pco_func *func, pco_ref src = instr->src[0]; unsigned offset = pco_ref_get_imm(instr->src[1]); + BITSET_SET(comps, dest.val); + assert(pco_ref_is_ssa(src)); assert(pco_ref_is_ssa(dest)); + struct vec_override *vec_override = + _mesa_hash_table_u64_search(overrides, src.val); + + if (vec_override) { + src = vec_override->ref; + offset += vec_override->offset; + } + struct vec_override *src_override = rzalloc_size(overrides, sizeof(*src_override)); src_override->ref = src; @@ -284,6 +328,27 @@ static bool pco_ra_func(pco_func *func, } } + /* Extend lifetimes of non-overriden vecs that have comp instructions. */ + pco_foreach_instr_in_func (instr, func) { + if (instr->op != PCO_OP_COMP) + continue; + + pco_ref dest = instr->dest[0]; + pco_ref src_vec = instr->src[0]; + + struct vec_override *vec_override = + _mesa_hash_table_u64_search(overrides, src_vec.val); + + /* Already taken care of. */ + if (vec_override) { + assert(live_ranges[src_vec.val].start == ~0U && + live_ranges[src_vec.val].end == 0); + continue; + } + + pco_extend_live_range(src_vec, dest, instr, overrides, live_ranges); + } + /* Build interference graph from overlapping live ranges. */ for (unsigned var0 = 0; var0 < num_vars; ++var0) { for (unsigned var1 = var0 + 1; var1 < num_vars; ++var1) { @@ -326,8 +391,10 @@ static bool pco_ra_func(pco_func *func, unsigned vtxins = 0; unsigned interns = 0; pco_foreach_instr_in_func_safe (instr, func) { + /* if (PCO_DEBUG_PRINT(RA)) pco_print_shader(func->parent_shader, stdout, "ra debug"); + */ /* Insert movs for scalar components of super vecs. */ if (instr->op == PCO_OP_VEC) { @@ -345,23 +412,44 @@ static bool pco_ra_func(pco_func *func, pco_foreach_instr_src (psrc, instr) { if (!pco_ref_is_ssa(*psrc) || - !_mesa_hash_table_u64_search(overrides, psrc->val)) { + !_mesa_hash_table_u64_search(overrides, psrc->val) || + BITSET_TEST(comps, psrc->val)) { unsigned chans = pco_ref_get_chans(*psrc); + unsigned temp_src_base = ~0U; + if (pco_ref_is_ssa(*psrc)) { + temp_src_base = ra_get_node_reg(ra_graph, psrc->val); + + struct vec_override *src_override = + _mesa_hash_table_u64_search(overrides, psrc->val); + if (src_override) { + temp_src_base = + ra_get_node_reg(ra_graph, src_override->ref.val); + temp_src_base += src_override->offset; + } + } else if (pco_ref_is_vreg(*psrc)) { + temp_src_base = + ra_get_node_reg(ra_graph, psrc->val + num_ssas); + } + + enum pco_exec_cnd exec_cnd = pco_instr_get_exec_cnd(instr); for (unsigned u = 0; u < chans; ++u) { pco_ref dest = pco_ref_hwreg(temp_dest_base + offset, PCO_REG_CLASS_TEMP); dest = pco_ref_offset(dest, u); - pco_ref src = - pco_ref_is_ssa(*psrc) - ? pco_ref_hwreg(ra_get_node_reg(ra_graph, psrc->val), - PCO_REG_CLASS_TEMP) - : pco_ref_chans(*psrc, 1); + pco_ref src; + if (pco_ref_is_ssa(*psrc) || pco_ref_is_vreg(*psrc)) + src = pco_ref_hwreg(temp_src_base, PCO_REG_CLASS_TEMP); + else + src = pco_ref_chans(*psrc, 1); + src = pco_ref_offset(src, u); - if (!pco_refs_are_equal(src, dest)) - pco_mbyp(&b, dest, src); + pco_ref_xfer_mods(&src, psrc, false); + + if (!pco_refs_are_equal(src, dest, true)) + pco_mbyp(&b, dest, src, .exec_cnd = exec_cnd); } temps = MAX2(temps, temp_dest_base + offset + chans); @@ -426,6 +514,13 @@ static bool pco_ra_func(pco_func *func, psrc->reg_class = PCO_REG_CLASS_TEMP; psrc->val = val; } + + /* Drop no-ops. */ + if (instr->op == PCO_OP_MBYP && + (pco_ref_is_ssa(instr->src[0]) || pco_ref_is_vreg(instr->src[0])) && + pco_refs_are_equal(instr->src[0], instr->dest[0], true)) { + pco_instr_delete(instr); + } } ralloc_free(ra_regs); diff --git a/src/imagination/pco/pco_trans_nir.c b/src/imagination/pco/pco_trans_nir.c index aa2b21ba374..422e8992e73 100644 --- a/src/imagination/pco/pco_trans_nir.c +++ b/src/imagination/pco/pco_trans_nir.c @@ -806,7 +806,8 @@ try_collate_vec(pco_ref *src, pco_instr *from, pco_ref vec, unsigned vec_chans) unsigned comp_idx = pco_ref_get_imm(parent_instr->src[1]); ASSERTED unsigned chans = pco_ref_get_chans(comp_src); - if (!pco_refs_are_equal(comp_src, vec)) + /* TODO: can this be true? */ + if (!pco_refs_are_equal(comp_src, vec, false)) return pco_ref_null(); assert(chans == vec_chans);