From 2db53101c1214a388e051e0a12db52b3e464f6b9 Mon Sep 17 00:00:00 2001 From: Simon Perretta Date: Wed, 1 Jan 2025 13:45:28 +0000 Subject: [PATCH] pco: add virtual register support Signed-off-by: Simon Perretta Acked-by: Erik Faye-Lund Part-of: --- src/imagination/.clang-format | 4 + src/imagination/pco/pco_internal.h | 39 ++++++++++ src/imagination/pco/pco_ra.c | 115 +++++++++++++++++++++++------ 3 files changed, 135 insertions(+), 23 deletions(-) diff --git a/src/imagination/.clang-format b/src/imagination/.clang-format index ba2a4a65e81..937b4855461 100644 --- a/src/imagination/.clang-format +++ b/src/imagination/.clang-format @@ -264,6 +264,8 @@ ForEachMacros: [ 'pco_foreach_instr_dest_from', 'pco_foreach_instr_dest_ssa', 'pco_foreach_instr_dest_ssa_from', + 'pco_foreach_instr_dest_vreg', + 'pco_foreach_instr_dest_vreg_ssa', 'pco_foreach_instr_in_block', 'pco_foreach_instr_in_block_from', 'pco_foreach_instr_in_block_from_rev', @@ -282,6 +284,8 @@ ForEachMacros: [ 'pco_foreach_instr_src_from', 'pco_foreach_instr_src_ssa', 'pco_foreach_instr_src_ssa_from', + 'pco_foreach_instr_src_vreg', + 'pco_foreach_instr_src_vreg_ssa', 'pco_foreach_loop_in_func', 'pco_foreach_loop_in_func_from', 'pco_foreach_loop_in_func_from_rev', diff --git a/src/imagination/pco/pco_internal.h b/src/imagination/pco/pco_internal.h index 8d86f1cb0b3..7f39facee64 100644 --- a/src/imagination/pco/pco_internal.h +++ b/src/imagination/pco/pco_internal.h @@ -340,6 +340,7 @@ typedef struct _pco_func { struct hash_table_u64 *vec_infos; unsigned next_ssa; /** Next SSA node index. */ + unsigned next_vreg; /** Next virtual register index. */ unsigned next_instr; /** Next instruction index. */ unsigned next_igrp; /** Next igrp index. */ unsigned next_block; /** Next block index. */ @@ -638,6 +639,14 @@ PCO_DEFINE_CAST(pco_cf_node_as_func, pco_foreach_instr_dest_from (pdest, instr, pdest_from) \ if (pco_ref_is_ssa(*pdest)) +#define pco_foreach_instr_dest_vreg(pdest, instr) \ + pco_foreach_instr_dest (pdest, instr) \ + if (pco_ref_is_vreg(*pdest)) + +#define pco_foreach_instr_dest_vreg_ssa(pdest, instr) \ + pco_foreach_instr_dest (pdest, instr) \ + if (pco_ref_is_vreg(*pdest) || pco_ref_is_ssa(*pdest)) + #define pco_foreach_instr_src(psrc, instr) \ for (pco_ref *psrc = &instr->src[0]; psrc < &instr->src[instr->num_srcs]; \ ++psrc) @@ -654,6 +663,14 @@ PCO_DEFINE_CAST(pco_cf_node_as_func, pco_foreach_instr_src_from (psrc, instr, psrc_from) \ if (pco_ref_is_ssa(*psrc)) +#define pco_foreach_instr_src_vreg(psrc, instr) \ + pco_foreach_instr_src (psrc, instr) \ + if (pco_ref_is_vreg(*psrc)) + +#define pco_foreach_instr_src_vreg_ssa(psrc, instr) \ + pco_foreach_instr_src (psrc, instr) \ + if (pco_ref_is_vreg(*psrc) || pco_ref_is_ssa(*psrc)) + #define pco_cf_node_head(list) exec_node_data_head(pco_cf_node, list, node) #define pco_cf_node_tail(list) exec_node_data_tail(pco_cf_node, list, node) #define pco_cf_node_next(cf_node) \ @@ -1574,6 +1591,17 @@ static inline bool pco_ref_is_ssa(pco_ref ref) return ref.type == PCO_REF_TYPE_SSA; } +/** + * \brief Returns whether a reference is a virtual register. + * + * \param[in] ref PCO reference. + * \return True if the reference is a virtual register. + */ +static inline bool pco_ref_is_vreg(pco_ref ref) +{ + return ref.type == PCO_REF_TYPE_REG && ref.reg_class == PCO_REG_CLASS_VIRT; +} + /** * \brief Returns whether a reference is a register. * @@ -2012,6 +2040,17 @@ static inline pco_ref pco_ref_vreg(unsigned index) }; } +/** + * \brief Builds and returns a new virtual register. + * + * \param[in,out] func The function. + * \return Virtual register reference. + */ +static inline pco_ref pco_ref_new_vreg(pco_func *func) +{ + return pco_ref_vreg(func->next_vreg++); +} + /** * \brief Builds and returns a scalar hardware register reference. * diff --git a/src/imagination/pco/pco_ra.c b/src/imagination/pco/pco_ra.c index 320e55562f8..933c3f22817 100644 --- a/src/imagination/pco/pco_ra.c +++ b/src/imagination/pco/pco_ra.c @@ -79,23 +79,32 @@ static bool pco_ra_func(pco_func *func, * TODO: track successors/predecessors. */ + unsigned num_ssas = func->next_ssa; + unsigned num_vregs = func->next_vreg; + unsigned num_vars = num_ssas + num_vregs; + /* Collect used bit sizes. */ - uint8_t ssa_bits = 0; + uint8_t used_bits = 0; pco_foreach_instr_in_func (instr, func) { pco_foreach_instr_dest_ssa (pdest, instr) { - ssa_bits |= (1 << pdest->bits); + used_bits |= (1 << pdest->bits); } } + /* vregs are always 32x1. */ + if (num_vregs > 0) { + used_bits |= (1 << PCO_BITS_32); + } + /* No registers to allocate. */ - if (!ssa_bits) + if (!used_bits) return false; - /* 64-bit SSA should've been lowered by now. */ - assert(!(ssa_bits & (1 << PCO_BITS_64))); + /* 64-bit vars should've been lowered by now. */ + assert(!(used_bits & (1 << PCO_BITS_64))); /* TODO: support multiple bit sizes. */ - bool only_32bit = ssa_bits == (1 << PCO_BITS_32); + bool only_32bit = used_bits == (1 << PCO_BITS_32); assert(only_32bit); struct ra_regs *ra_regs = @@ -181,6 +190,14 @@ static bool pco_ra_func(pco_func *func, } } + /* vregs are always 32x1. */ + if (num_vregs > 0) { + if (!_mesa_hash_table_u64_search(ra_classes, 1)) { + struct ra_class *ra_class = ra_alloc_contig_reg_class(ra_regs, 1); + _mesa_hash_table_u64_insert(ra_classes, 1, ra_class); + } + } + /* Assign registers to classes. */ hash_table_u64_foreach (ra_classes, entry) { const unsigned stride = entry.key; @@ -192,15 +209,14 @@ static bool pco_ra_func(pco_func *func, ra_set_finalize(ra_regs, NULL); - struct ra_graph *ra_graph = - ra_alloc_interference_graph(ra_regs, func->next_ssa); + struct ra_graph *ra_graph = ra_alloc_interference_graph(ra_regs, num_vars); ralloc_steal(ra_regs, ra_graph); /* Allocate and calculate live ranges. */ struct live_range *live_ranges = - rzalloc_array_size(ra_regs, sizeof(*live_ranges), func->next_ssa); + rzalloc_array_size(ra_regs, sizeof(*live_ranges), num_vars); - for (unsigned u = 0; u < func->next_ssa; ++u) + for (unsigned u = 0; u < num_vars; ++u) live_ranges[u].start = ~0U; pco_foreach_instr_in_func (instr, func) { @@ -238,16 +254,44 @@ static bool pco_ra_func(pco_func *func, live_ranges[src.val].end = MAX2(live_ranges[src.val].end, instr->index); } + + pco_foreach_instr_dest_vreg (pdest, instr) { + pco_ref dest = *pdest; + + /* Place vregs after ssa vars. */ + dest.val += num_ssas; + + live_ranges[dest.val].start = + MIN2(live_ranges[dest.val].start, instr->index); + + /* Set class if it hasn't already been set up in an override. */ + unsigned chans = pco_ref_get_chans(dest); + struct ra_class *ra_class = + _mesa_hash_table_u64_search(ra_classes, chans); + assert(ra_class); + + ra_set_node_class(ra_graph, dest.val, ra_class); + } + + pco_foreach_instr_src_vreg (psrc, instr) { + pco_ref src = *psrc; + + /* Place vregs after ssa vars. */ + src.val += num_ssas; + + live_ranges[src.val].end = + MAX2(live_ranges[src.val].end, instr->index); + } } /* Build interference graph from overlapping live ranges. */ - for (unsigned ssa0 = 0; ssa0 < func->next_ssa; ++ssa0) { - for (unsigned ssa1 = ssa0 + 1; ssa1 < func->next_ssa; ++ssa1) { + for (unsigned var0 = 0; var0 < num_vars; ++var0) { + for (unsigned var1 = var0 + 1; var1 < num_vars; ++var1) { /* If the live ranges overlap, the register nodes interfere. */ - if ((live_ranges[ssa0].start != ~0U && live_ranges[ssa1].end != ~0U) && - !(live_ranges[ssa0].start >= live_ranges[ssa1].end || - live_ranges[ssa1].start >= live_ranges[ssa0].end)) { - ra_add_node_interference(ra_graph, ssa0, ssa1); + if ((live_ranges[var0].start != ~0U && live_ranges[var1].end != ~0U) && + !(live_ranges[var0].start >= live_ranges[var1].end || + live_ranges[var1].start >= live_ranges[var0].end)) { + ra_add_node_interference(ra_graph, var0, var1); } } } @@ -258,8 +302,12 @@ static bool pco_ra_func(pco_func *func, if (PCO_DEBUG_PRINT(RA)) { printf("RA live ranges:\n"); - for (unsigned u = 0; u < func->next_ssa; ++u) - printf(" %%%u: %u, %u\n", u, live_ranges[u].start, live_ranges[u].end); + for (unsigned u = 0; u < num_vars; ++u) + printf(" %c%u: %u, %u\n", + u >= num_ssas ? '$' : '%', + u >= num_ssas ? u - num_ssas : u, + live_ranges[u].start, + live_ranges[u].end); if (_mesa_hash_table_u64_num_entries(overrides)) { printf("RA overrides:\n"); @@ -273,7 +321,7 @@ static bool pco_ra_func(pco_func *func, } } - /* Replace SSA regs with allocated registers. */ + /* Replace vars with allocated registers. */ unsigned temps = 0; unsigned vtxins = 0; unsigned interns = 0; @@ -360,6 +408,24 @@ static bool pco_ra_func(pco_func *func, psrc->reg_class = PCO_REG_CLASS_TEMP; psrc->val = val; } + + pco_foreach_instr_dest_vreg (pdest, instr) { + unsigned val = ra_get_node_reg(ra_graph, pdest->val + num_ssas); + unsigned dest_temps = val + 1; + + pdest->type = PCO_REF_TYPE_REG; + pdest->reg_class = PCO_REG_CLASS_TEMP; + pdest->val = val; + temps = MAX2(temps, dest_temps); + } + + pco_foreach_instr_src_vreg (psrc, instr) { + unsigned val = ra_get_node_reg(ra_graph, psrc->val + num_ssas); + + psrc->type = PCO_REF_TYPE_REG; + psrc->reg_class = PCO_REG_CLASS_TEMP; + psrc->val = val; + } } ralloc_free(ra_regs); @@ -367,10 +433,13 @@ static bool pco_ra_func(pco_func *func, func->temps = temps; if (PCO_DEBUG_PRINT(RA)) { - printf("RA allocated %u temps, %u vtxins, %u interns.\n", - temps, - vtxins, - interns); + printf( + "RA allocated %u temps, %u vtxins, %u interns from %u SSA vars, %u vregs.\n", + temps, + vtxins, + interns, + num_ssas, + num_vregs); } return true;