1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2022 Imagination Technologies Ltd. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 5bf215546Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal 6bf215546Sopenharmony_ci * in the Software without restriction, including without limitation the rights 7bf215546Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8bf215546Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is 9bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18bf215546Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include <stddef.h> 25bf215546Sopenharmony_ci#include <stdint.h> 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "rogue_operand.h" 28bf215546Sopenharmony_ci#include "rogue_regalloc.h" 29bf215546Sopenharmony_ci#include "rogue_shader.h" 30bf215546Sopenharmony_ci#include "rogue_util.h" 31bf215546Sopenharmony_ci#include "util/hash_table.h" 32bf215546Sopenharmony_ci#include "util/list.h" 33bf215546Sopenharmony_ci#include "util/ralloc.h" 34bf215546Sopenharmony_ci#include "util/register_allocate.h" 35bf215546Sopenharmony_ci#include "util/u_dynarray.h" 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci/** 38bf215546Sopenharmony_ci * \file rogue_regalloc.c 39bf215546Sopenharmony_ci * 40bf215546Sopenharmony_ci * \brief Contains register allocation helper functions. 41bf215546Sopenharmony_ci */ 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci/** 44bf215546Sopenharmony_ci * \brief Sets up the register data with the classes to be used for allocation. 45bf215546Sopenharmony_ci * 46bf215546Sopenharmony_ci * \param[in] data The register data array. 47bf215546Sopenharmony_ci */ 48bf215546Sopenharmony_cistatic void 49bf215546Sopenharmony_cirogue_reg_data_init(struct rogue_reg_data data[static ROGUE_REG_CLASS_COUNT]) 50bf215546Sopenharmony_ci{ 51bf215546Sopenharmony_ci data[ROGUE_REG_CLASS_TEMP].type = ROGUE_OPERAND_TYPE_REG_TEMP; 52bf215546Sopenharmony_ci data[ROGUE_REG_CLASS_TEMP].count = ROGUE_MAX_REG_TEMP; 53bf215546Sopenharmony_ci data[ROGUE_REG_CLASS_TEMP].stride = 1; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci data[ROGUE_REG_CLASS_VEC4].type = ROGUE_OPERAND_TYPE_REG_INTERNAL; 56bf215546Sopenharmony_ci data[ROGUE_REG_CLASS_VEC4].count = ROGUE_MAX_REG_INTERNAL; 57bf215546Sopenharmony_ci data[ROGUE_REG_CLASS_VEC4].stride = 4; 58bf215546Sopenharmony_ci} 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci/** 61bf215546Sopenharmony_ci * \brief Initializes the Rogue register allocation context. 62bf215546Sopenharmony_ci * 63bf215546Sopenharmony_ci * \param[in] mem_ctx The memory context for the ra context. 64bf215546Sopenharmony_ci * \return A rogue_ra * if successful, or NULL if unsuccessful. 65bf215546Sopenharmony_ci */ 66bf215546Sopenharmony_cistruct rogue_ra *rogue_ra_init(void *mem_ctx) 67bf215546Sopenharmony_ci{ 68bf215546Sopenharmony_ci struct rogue_ra *ra; 69bf215546Sopenharmony_ci size_t total_regs = 0; 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci ra = rzalloc_size(mem_ctx, sizeof(*ra)); 72bf215546Sopenharmony_ci if (!ra) 73bf215546Sopenharmony_ci return NULL; 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci /* Initialize the register class data. */ 76bf215546Sopenharmony_ci rogue_reg_data_init(ra->reg_data); 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci /* Count up the registers classes and set up their offsets. 79bf215546Sopenharmony_ci * 80bf215546Sopenharmony_ci * The physical register numbers are sequential, even if the 81bf215546Sopenharmony_ci * registers are from different banks, so keeping track of 82bf215546Sopenharmony_ci * the offset means we can get the true physical register 83bf215546Sopenharmony_ci * number back after allocation. 84bf215546Sopenharmony_ci */ 85bf215546Sopenharmony_ci for (size_t u = 0; u < ARRAY_SIZE(ra->reg_data); ++u) { 86bf215546Sopenharmony_ci ra->reg_data[u].offset = total_regs; 87bf215546Sopenharmony_ci total_regs += ra->reg_data[u].count; 88bf215546Sopenharmony_ci } 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci /* Create a register set for allocation. */ 91bf215546Sopenharmony_ci ra->regs = ra_alloc_reg_set(ra, total_regs, true); 92bf215546Sopenharmony_ci if (!ra->regs) { 93bf215546Sopenharmony_ci ralloc_free(ra); 94bf215546Sopenharmony_ci return NULL; 95bf215546Sopenharmony_ci } 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci /* Create the register class for the temps. */ 98bf215546Sopenharmony_ci ra->reg_data[ROGUE_REG_CLASS_TEMP].class = 99bf215546Sopenharmony_ci ra_alloc_contig_reg_class(ra->regs, 1); 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci /* Create the register class for vec4 registers 102bf215546Sopenharmony_ci * (using the internal register bank). 103bf215546Sopenharmony_ci */ 104bf215546Sopenharmony_ci ra->reg_data[ROGUE_REG_CLASS_VEC4].class = 105bf215546Sopenharmony_ci ra_alloc_contig_reg_class(ra->regs, 4); 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_ci /* Populate the register classes. */ 108bf215546Sopenharmony_ci for (size_t u = 0; u < ARRAY_SIZE(ra->reg_data); ++u) { 109bf215546Sopenharmony_ci struct rogue_reg_data *reg_data = &ra->reg_data[u]; 110bf215546Sopenharmony_ci size_t offset = reg_data->offset; 111bf215546Sopenharmony_ci size_t end = reg_data->offset + reg_data->count; 112bf215546Sopenharmony_ci size_t stride = reg_data->stride; 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci for (size_t r = offset; r < end; r += stride) 115bf215546Sopenharmony_ci ra_class_add_reg(reg_data->class, r); 116bf215546Sopenharmony_ci } 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci /* Finalize the set (no early conflicts passed along for now). */ 119bf215546Sopenharmony_ci ra_set_finalize(ra->regs, NULL); 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci return ra; 122bf215546Sopenharmony_ci} 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci/** 125bf215546Sopenharmony_ci * \brief The range for which a (virtual) register is live, and its references. 126bf215546Sopenharmony_ci */ 127bf215546Sopenharmony_cistruct live_range { 128bf215546Sopenharmony_ci size_t start; 129bf215546Sopenharmony_ci size_t end; 130bf215546Sopenharmony_ci enum rogue_reg_class class; 131bf215546Sopenharmony_ci struct util_dynarray operand_refs; 132bf215546Sopenharmony_ci}; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci/** 135bf215546Sopenharmony_ci * \brief Performs register allocation. 136bf215546Sopenharmony_ci * 137bf215546Sopenharmony_ci * \param[in] instr_list A linked list of instructions with virtual registers to 138bf215546Sopenharmony_ci * be allocated. 139bf215546Sopenharmony_ci * \param[in] ra The register allocation context. 140bf215546Sopenharmony_ci */ 141bf215546Sopenharmony_cibool rogue_ra_alloc(struct list_head *instr_list, 142bf215546Sopenharmony_ci struct rogue_ra *ra, 143bf215546Sopenharmony_ci size_t *temps_used, 144bf215546Sopenharmony_ci size_t *internals_used) 145bf215546Sopenharmony_ci{ 146bf215546Sopenharmony_ci /* Used for ra_alloc_interference_graph() as it doesn't 147bf215546Sopenharmony_ci * like having gaps (e.g. with v0, v2 count = 3 rather 148bf215546Sopenharmony_ci * than 2). 149bf215546Sopenharmony_ci */ 150bf215546Sopenharmony_ci size_t max_vreg = 0; 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci struct hash_table *reg_ht = 153bf215546Sopenharmony_ci _mesa_hash_table_create(ra, _mesa_hash_uint, _mesa_key_uint_equal); 154bf215546Sopenharmony_ci if (!reg_ht) 155bf215546Sopenharmony_ci return false; 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci /* Calculate live ranges for virtual registers. */ 158bf215546Sopenharmony_ci size_t ip = 0U; /* "Instruction pointer". */ 159bf215546Sopenharmony_ci foreach_instr (instr, instr_list) { 160bf215546Sopenharmony_ci for (size_t u = 0U; u < instr->num_operands; ++u) { 161bf215546Sopenharmony_ci struct hash_entry *entry; 162bf215546Sopenharmony_ci struct live_range *range; 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ci if (instr->operands[u].type != ROGUE_OPERAND_TYPE_VREG) 165bf215546Sopenharmony_ci continue; 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci entry = 168bf215546Sopenharmony_ci _mesa_hash_table_search(reg_ht, &instr->operands[u].vreg.number); 169bf215546Sopenharmony_ci if (!entry) { 170bf215546Sopenharmony_ci /* First use of this virtual register: initialize live range. */ 171bf215546Sopenharmony_ci /* TODO: Error handling. */ 172bf215546Sopenharmony_ci range = rzalloc_size(reg_ht, sizeof(*range)); 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci range->start = ip; 175bf215546Sopenharmony_ci range->end = ip; 176bf215546Sopenharmony_ci range->class = instr->operands[u].vreg.is_vector 177bf215546Sopenharmony_ci ? ROGUE_REG_CLASS_VEC4 178bf215546Sopenharmony_ci : ROGUE_REG_CLASS_TEMP; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci entry = _mesa_hash_table_insert(reg_ht, 181bf215546Sopenharmony_ci &instr->operands[u].vreg.number, 182bf215546Sopenharmony_ci range); 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci max_vreg = MAX2(max_vreg, instr->operands[u].vreg.number); 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci util_dynarray_init(&range->operand_refs, range); 187bf215546Sopenharmony_ci } else { 188bf215546Sopenharmony_ci /* Subsequent uses: update live range end. */ 189bf215546Sopenharmony_ci range = entry->data; 190bf215546Sopenharmony_ci range->end = MAX2(range->end, ip); 191bf215546Sopenharmony_ci assert(range->class == (instr->operands[u].vreg.is_vector 192bf215546Sopenharmony_ci ? ROGUE_REG_CLASS_VEC4 193bf215546Sopenharmony_ci : ROGUE_REG_CLASS_TEMP)); 194bf215546Sopenharmony_ci } 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci /* Save a reference to the operand. */ 197bf215546Sopenharmony_ci util_dynarray_append(&range->operand_refs, 198bf215546Sopenharmony_ci struct rogue_operand *, 199bf215546Sopenharmony_ci &instr->operands[u]); 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci ++ip; 202bf215546Sopenharmony_ci } 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci /* Initialize the interference graph. */ 205bf215546Sopenharmony_ci struct ra_graph *g = ra_alloc_interference_graph(ra->regs, max_vreg + 1); 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci /* Set each virtual register to the appropriate class. */ 208bf215546Sopenharmony_ci hash_table_foreach (reg_ht, entry) { 209bf215546Sopenharmony_ci const uint32_t *vreg = entry->key; 210bf215546Sopenharmony_ci struct live_range *range = entry->data; 211bf215546Sopenharmony_ci struct ra_class *class = ra->reg_data[range->class].class; 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci ra_set_node_class(g, *vreg, class); 214bf215546Sopenharmony_ci /* TODO: ra_set_node_spill_cost(g, *vreg, cost); */ 215bf215546Sopenharmony_ci } 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci /* Build interference graph from overlapping live ranges. */ 218bf215546Sopenharmony_ci hash_table_foreach (reg_ht, entry_first) { 219bf215546Sopenharmony_ci const uint32_t *vreg_first = entry_first->key; 220bf215546Sopenharmony_ci struct live_range *range_first = entry_first->data; 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_ci hash_table_foreach (reg_ht, entry_second) { 223bf215546Sopenharmony_ci const uint32_t *vreg_second = entry_second->key; 224bf215546Sopenharmony_ci struct live_range *range_second = entry_second->data; 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci if (*vreg_first == *vreg_second) 227bf215546Sopenharmony_ci continue; 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci /* If the live ranges overlap, those register nodes interfere. */ 230bf215546Sopenharmony_ci if (!(range_first->start >= range_second->end || 231bf215546Sopenharmony_ci range_second->start >= range_first->end)) { 232bf215546Sopenharmony_ci ra_add_node_interference(g, *vreg_first, *vreg_second); 233bf215546Sopenharmony_ci } 234bf215546Sopenharmony_ci } 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci /* Add node interferences such that the same register can't be used for 238bf215546Sopenharmony_ci * both an instruction's source and destination. 239bf215546Sopenharmony_ci */ 240bf215546Sopenharmony_ci foreach_instr (instr, instr_list) { 241bf215546Sopenharmony_ci for (size_t u = 0U; u < instr->num_operands; ++u) { 242bf215546Sopenharmony_ci if (instr->operands[u].type != ROGUE_OPERAND_TYPE_VREG) 243bf215546Sopenharmony_ci continue; 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci /* Operand 0 (if it exists and is virtual) is always 246bf215546Sopenharmony_ci * the destination register. 247bf215546Sopenharmony_ci */ 248bf215546Sopenharmony_ci if (u > 0 && instr->operands[0].type == ROGUE_OPERAND_TYPE_VREG) 249bf215546Sopenharmony_ci ra_add_node_interference(g, 250bf215546Sopenharmony_ci instr->operands[0].vreg.number, 251bf215546Sopenharmony_ci instr->operands[u].vreg.number); 252bf215546Sopenharmony_ci } 253bf215546Sopenharmony_ci } 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci /* Perform register allocation. */ 256bf215546Sopenharmony_ci /* TODO: Spilling support. */ 257bf215546Sopenharmony_ci assert(ra_allocate(g)); 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci /* Replace virtual registers with allocated physical registers. 260bf215546Sopenharmony_ci * N.B. This is a destructive process as it overwrites the hash table key! 261bf215546Sopenharmony_ci */ 262bf215546Sopenharmony_ci hash_table_foreach (reg_ht, entry) { 263bf215546Sopenharmony_ci uint32_t vreg = *(uint32_t *)entry->key; 264bf215546Sopenharmony_ci unsigned phy_reg = ra_get_node_reg(g, vreg); 265bf215546Sopenharmony_ci struct live_range *range = entry->data; 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci struct rogue_reg_data *reg_data = &ra->reg_data[range->class]; 268bf215546Sopenharmony_ci enum rogue_operand_type type = reg_data->type; 269bf215546Sopenharmony_ci size_t reg_offset = reg_data->offset; 270bf215546Sopenharmony_ci size_t *num_used = ®_data->num_used; 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci util_dynarray_foreach (&range->operand_refs, 273bf215546Sopenharmony_ci struct rogue_operand *, 274bf215546Sopenharmony_ci operand_ptr) { 275bf215546Sopenharmony_ci size_t num = phy_reg - reg_offset; 276bf215546Sopenharmony_ci struct rogue_operand *operand = *operand_ptr; 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci assert(operand->type == ROGUE_OPERAND_TYPE_VREG); 279bf215546Sopenharmony_ci assert(operand->vreg.number == vreg); 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci /* Index the component of emulated vec4 registers. */ 282bf215546Sopenharmony_ci if (operand->vreg.is_vector && 283bf215546Sopenharmony_ci operand->vreg.component != ROGUE_COMPONENT_ALL) 284bf215546Sopenharmony_ci num += operand->vreg.component; 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci operand->type = type; 287bf215546Sopenharmony_ci operand->reg.number = num; 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci *num_used = MAX2(*num_used, operand->reg.number); 290bf215546Sopenharmony_ci } 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ci util_dynarray_fini(&range->operand_refs); 293bf215546Sopenharmony_ci _mesa_hash_table_remove(reg_ht, entry); 294bf215546Sopenharmony_ci } 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_ci /* Registers used = max reg number + 1. */ 297bf215546Sopenharmony_ci for (size_t u = 0; u < ARRAY_SIZE(ra->reg_data); ++u) 298bf215546Sopenharmony_ci if (ra->reg_data[u].num_used) 299bf215546Sopenharmony_ci ++ra->reg_data[u].num_used; 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci /* Pass back the registers used. */ 302bf215546Sopenharmony_ci if (temps_used) 303bf215546Sopenharmony_ci *temps_used = ra->reg_data[ROGUE_REG_CLASS_TEMP].num_used; 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci if (internals_used) 306bf215546Sopenharmony_ci *internals_used = ra->reg_data[ROGUE_REG_CLASS_VEC4].num_used; 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci ralloc_free(g); 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci _mesa_hash_table_destroy(reg_ht, NULL); 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_ci return true; 313bf215546Sopenharmony_ci} 314