diff --git a/src/imagination/rogue/passes/rogue_regalloc.c b/src/imagination/rogue/passes/rogue_regalloc.c index b643b266c7a..d46ef62044f 100644 --- a/src/imagination/rogue/passes/rogue_regalloc.c +++ b/src/imagination/rogue/passes/rogue_regalloc.c @@ -23,10 +23,12 @@ #include "rogue.h" #include "util/macros.h" +#include "util/u_qsort.h" #include "util/ralloc.h" #include "util/register_allocate.h" #include +#include /** * \file rogue_regalloc.c @@ -41,6 +43,20 @@ typedef struct rogue_live_range { unsigned end; } rogue_live_range; +static int regarray_cmp(const void *lhs, const void *rhs, UNUSED void *arg) +{ + const rogue_regarray *l = lhs; + const rogue_regarray *r = rhs; + + /* Signs swapped for sorting largest->smallest. */ + if (l->size > r->size) + return -1; + else if (l->size < r->size) + return 1; + + return 0; +} + PUBLIC bool rogue_regalloc(rogue_shader *shader) { @@ -201,6 +217,7 @@ bool rogue_regalloc(rogue_shader *shader) rogue_regarray **parent_regarrays = rzalloc_array_size(shader, sizeof(*parent_regarrays), regarray_count); + /* Construct list of sorted parent regarrays. */ unsigned num_parent_regarrays = 0; rogue_foreach_regarray (regarray, shader) { if (regarray->parent || regarray->regs[0]->class != ROGUE_REG_CLASS_SSA) @@ -209,6 +226,12 @@ bool rogue_regalloc(rogue_shader *shader) parent_regarrays[num_parent_regarrays++] = regarray; } + util_qsort_r(parent_regarrays, + num_parent_regarrays, + sizeof(*parent_regarrays), + regarray_cmp, + NULL); + for (unsigned u = 0; u < num_parent_regarrays; ++u) { rogue_regarray *regarray = parent_regarrays[u]; @@ -219,9 +242,13 @@ bool rogue_regalloc(rogue_shader *shader) enum rogue_reg_class new_class = regalloc_info[ra_class].class; bool used = false; - for (unsigned r = 0; r < regarray->size; ++r) + for (unsigned r = 0; r < regarray->size; ++r) { used |= rogue_reg_is_used(shader, new_class, new_base_index + r); + if (used) + break; + } + /* First time using new regarray, modify in place. */ if (!used) { progress |= @@ -234,21 +261,7 @@ bool rogue_regalloc(rogue_shader *shader) regarray->size, new_class, new_base_index); - progress |= rogue_regarray_replace(regarray, new_regarray); - - /* Replace subarrays. */ - rogue_foreach_subarray_safe (subarray, regarray) { - unsigned idx_offset = - subarray->regs[0]->index - regarray->regs[0]->index; - new_regarray = rogue_regarray_cached(shader, - subarray->size, - new_class, - new_base_index + idx_offset); - progress |= rogue_regarray_replace(subarray, new_regarray); - rogue_regarray_delete(subarray); - } - - rogue_regarray_delete(regarray); + progress |= rogue_regarray_replace(shader, regarray, new_regarray); } } diff --git a/src/imagination/rogue/rogue.c b/src/imagination/rogue/rogue.c index d8f23bc5f49..c3563f39ce4 100644 --- a/src/imagination/rogue/rogue.c +++ b/src/imagination/rogue/rogue.c @@ -475,10 +475,23 @@ static rogue_regarray *rogue_regarray_create(rogue_shader *shader, for (unsigned u = 0; u < common_regarray->size; ++u) common_regarray->regs[u]->regarray = regarray; + /* Steal its children. */ + rogue_foreach_subarray_safe (subarray, common_regarray) { + unsigned parent_index = common_regarray->regs[0]->index; + unsigned child_index = subarray->regs[0]->index; + assert(child_index >= parent_index); + + subarray->parent = regarray; + subarray->regs = &parent_regptr[child_index - parent_index]; + + list_del(&subarray->child_link); + list_addtail(&subarray->child_link, ®array->children); + } + common_regarray->parent = regarray; ralloc_free(common_regarray->regs); common_regarray->regs = parent_regptr; - list_addtail(®array->children, &common_regarray->child_link); + list_addtail(&common_regarray->child_link, ®array->children); } else { /* We share registers with another regarray, and we are a subset of it. */ diff --git a/src/imagination/rogue/rogue.h b/src/imagination/rogue/rogue.h index 4afc6e91927..e0262ab80f7 100644 --- a/src/imagination/rogue/rogue.h +++ b/src/imagination/rogue/rogue.h @@ -2379,11 +2379,15 @@ static inline bool rogue_src_regarray_replace(rogue_regarray_use *use, return true; } -static inline bool rogue_regarray_replace(rogue_regarray *old_regarray, +static inline bool rogue_regarray_replace(rogue_shader *shader, + rogue_regarray *old_regarray, rogue_regarray *new_regarray) { bool replaced = true; + assert(!old_regarray->parent); + assert(!new_regarray->parent); + rogue_foreach_regarray_write_safe (write, old_regarray) { replaced &= rogue_dst_regarray_replace(write, new_regarray); } @@ -2392,8 +2396,31 @@ static inline bool rogue_regarray_replace(rogue_regarray *old_regarray, replaced &= rogue_src_regarray_replace(use, new_regarray); } - /* N.B. The old regarray isn't automatically deleted here, this needs to be - * done manually. */ + enum rogue_reg_class new_class = new_regarray->regs[0]->class; + unsigned new_base_index = new_regarray->regs[0]->index; + + /* Replace subarrays. */ + rogue_foreach_subarray_safe (old_subarray, old_regarray) { + unsigned idx_offset = + old_subarray->regs[0]->index - old_regarray->regs[0]->index; + rogue_regarray *new_subarray = + rogue_regarray_cached(shader, + old_subarray->size, + new_class, + new_base_index + idx_offset); + + rogue_foreach_regarray_write_safe (write, old_subarray) { + replaced &= rogue_dst_regarray_replace(write, new_subarray); + } + + rogue_foreach_regarray_use_safe (use, old_subarray) { + replaced &= rogue_src_regarray_replace(use, new_subarray); + } + + rogue_regarray_delete(old_subarray); + } + + rogue_regarray_delete(old_regarray); return replaced; }