1bf215546Sopenharmony_ci/* -*- mesa-c++ -*- 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright (c) 2022 Collabora LTD 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Author: Gert Wollny <gert.wollny@collabora.com> 6bf215546Sopenharmony_ci * 7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 8bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 9bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 10bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub 11bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom 12bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 15bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 16bf215546Sopenharmony_ci * Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 22bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci */ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "sfn_debug.h" 28bf215546Sopenharmony_ci#include "sfn_ra.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include <cassert> 31bf215546Sopenharmony_ci#include <queue> 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_cinamespace r600 { 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_civoid ComponentInterference::prepare_row(int row) 36bf215546Sopenharmony_ci{ 37bf215546Sopenharmony_ci m_rows.resize(row + 1); 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci} 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_civoid ComponentInterference::add(size_t idx1, size_t idx2) 42bf215546Sopenharmony_ci{ 43bf215546Sopenharmony_ci assert(idx1 > idx2); 44bf215546Sopenharmony_ci assert(m_rows.size() > idx1); 45bf215546Sopenharmony_ci m_rows[idx1].push_back(idx2); 46bf215546Sopenharmony_ci m_rows[idx2].push_back(idx1); 47bf215546Sopenharmony_ci} 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ciInterference::Interference(LiveRangeMap& map): 51bf215546Sopenharmony_ci m_map(map) 52bf215546Sopenharmony_ci{ 53bf215546Sopenharmony_ci initialize(); 54bf215546Sopenharmony_ci} 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_civoid Interference::initialize() 57bf215546Sopenharmony_ci{ 58bf215546Sopenharmony_ci for(int i = 0; i < 4; ++i) { 59bf215546Sopenharmony_ci initialize(m_components_maps[i], m_map.component(i)); 60bf215546Sopenharmony_ci } 61bf215546Sopenharmony_ci} 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_civoid Interference::initialize(ComponentInterference& comp_interference, 64bf215546Sopenharmony_ci LiveRangeMap::ChannelLiveRange& clr) 65bf215546Sopenharmony_ci{ 66bf215546Sopenharmony_ci for (size_t row = 0; row < clr.size(); ++row) { 67bf215546Sopenharmony_ci auto& row_entry = clr[row]; 68bf215546Sopenharmony_ci comp_interference.prepare_row(row); 69bf215546Sopenharmony_ci for (size_t col = 0; col < row; ++col) { 70bf215546Sopenharmony_ci auto& col_entry = clr[col]; 71bf215546Sopenharmony_ci if (row_entry.m_end >= col_entry.m_start && 72bf215546Sopenharmony_ci row_entry.m_start <= col_entry.m_end) 73bf215546Sopenharmony_ci comp_interference.add(row, col); 74bf215546Sopenharmony_ci } 75bf215546Sopenharmony_ci } 76bf215546Sopenharmony_ci} 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_cistruct Group { 79bf215546Sopenharmony_ci int priority; 80bf215546Sopenharmony_ci std::array<PRegister, 4> channels; 81bf215546Sopenharmony_ci}; 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_cistatic inline bool operator < (const Group& lhs, const Group& rhs) 84bf215546Sopenharmony_ci{ 85bf215546Sopenharmony_ci return lhs.priority < rhs.priority; 86bf215546Sopenharmony_ci} 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ciusing GroupRegisters = std::priority_queue<Group>; 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_cistatic bool 91bf215546Sopenharmony_cigroup_allocation (LiveRangeMap& lrm, const Interference& interference, GroupRegisters& groups) 92bf215546Sopenharmony_ci{ 93bf215546Sopenharmony_ci int color = 0; 94bf215546Sopenharmony_ci // allocate grouped registers 95bf215546Sopenharmony_ci while (!groups.empty()) { 96bf215546Sopenharmony_ci auto group = groups.top(); 97bf215546Sopenharmony_ci groups.pop(); 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci int start_comp = 0; 100bf215546Sopenharmony_ci while (!group.channels[start_comp]) 101bf215546Sopenharmony_ci ++start_comp; 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci sfn_log << SfnLog::merge << "Color group with " << *group.channels[start_comp] << "\n"; 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci // don't restart registers for exports, we may be able tp merge the 106bf215546Sopenharmony_ci // export calls, is fthe registers are consecutive 107bf215546Sopenharmony_ci if (group.priority > 0) 108bf215546Sopenharmony_ci color = 0; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci while (color < 124) { 111bf215546Sopenharmony_ci /* Find the coloring for the first channel */ 112bf215546Sopenharmony_ci bool color_in_use = false; 113bf215546Sopenharmony_ci int comp = start_comp; 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci auto& adjecency = interference.row(start_comp, group.channels[comp]->index()); 116bf215546Sopenharmony_ci auto& regs = lrm.component(comp); 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci sfn_log << SfnLog::merge << "Try color "<< color; 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci for (auto adj : adjecency) { 121bf215546Sopenharmony_ci if (regs[adj].m_color == color) { 122bf215546Sopenharmony_ci color_in_use = true; 123bf215546Sopenharmony_ci sfn_log << SfnLog::merge << " in use\n"; 124bf215546Sopenharmony_ci break; 125bf215546Sopenharmony_ci } 126bf215546Sopenharmony_ci } 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci if (color_in_use) { 129bf215546Sopenharmony_ci ++color; 130bf215546Sopenharmony_ci continue; 131bf215546Sopenharmony_ci } 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci /* First channel color found, check whether it can be used for all channels */ 134bf215546Sopenharmony_ci while (comp < 4) { 135bf215546Sopenharmony_ci sfn_log << SfnLog::merge << " interference: "; 136bf215546Sopenharmony_ci if (group.channels[comp]) { 137bf215546Sopenharmony_ci auto& component_life_ranges = lrm.component(comp); 138bf215546Sopenharmony_ci auto& adjecencies = interference.row(comp, group.channels[comp]->index()); 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci for (auto adj_index : adjecencies) { 141bf215546Sopenharmony_ci sfn_log << SfnLog::merge << *component_life_ranges[adj_index].m_register << " "; 142bf215546Sopenharmony_ci if (component_life_ranges[adj_index].m_color == color) { 143bf215546Sopenharmony_ci color_in_use = true; 144bf215546Sopenharmony_ci sfn_log << SfnLog::merge << "used"; 145bf215546Sopenharmony_ci break; 146bf215546Sopenharmony_ci } 147bf215546Sopenharmony_ci } 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci if (color_in_use) 150bf215546Sopenharmony_ci break; 151bf215546Sopenharmony_ci } 152bf215546Sopenharmony_ci ++comp; 153bf215546Sopenharmony_ci } 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci /* We couldn't allocate all channels with this color, so try next */ 156bf215546Sopenharmony_ci if (color_in_use) { 157bf215546Sopenharmony_ci ++color; 158bf215546Sopenharmony_ci sfn_log << SfnLog::merge << "\n"; 159bf215546Sopenharmony_ci continue; 160bf215546Sopenharmony_ci } 161bf215546Sopenharmony_ci sfn_log << SfnLog::merge << " success\n"; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci /* Coloring successful */ 164bf215546Sopenharmony_ci for (auto reg : group.channels) { 165bf215546Sopenharmony_ci if (reg) { 166bf215546Sopenharmony_ci auto& vregs = lrm.component(reg->chan()); 167bf215546Sopenharmony_ci auto& vreg_cmp = vregs[reg->index()]; 168bf215546Sopenharmony_ci assert(vreg_cmp.m_start != -1 || vreg_cmp.m_end != -1); 169bf215546Sopenharmony_ci vreg_cmp.m_color = color; 170bf215546Sopenharmony_ci } 171bf215546Sopenharmony_ci } 172bf215546Sopenharmony_ci break; 173bf215546Sopenharmony_ci } 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci if (color == 124) 176bf215546Sopenharmony_ci return false; 177bf215546Sopenharmony_ci } 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci return true; 180bf215546Sopenharmony_ci} 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_cistatic bool 183bf215546Sopenharmony_ciscalar_allocation (LiveRangeMap& lrm, const Interference& interference) 184bf215546Sopenharmony_ci{ 185bf215546Sopenharmony_ci for (int comp = 0; comp < 4; ++comp) { 186bf215546Sopenharmony_ci auto& live_ranges = lrm.component(comp); 187bf215546Sopenharmony_ci for (auto& r : live_ranges) { 188bf215546Sopenharmony_ci if (r.m_color != -1) 189bf215546Sopenharmony_ci continue; 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci if (r.m_start == -1 && 192bf215546Sopenharmony_ci r.m_end == -1) 193bf215546Sopenharmony_ci continue; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci sfn_log << SfnLog::merge << "Color " << *r.m_register << "\n"; 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci auto& adjecency = interference.row(comp, r.m_register->index()); 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci int color = 0; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci while (color < 124) { 202bf215546Sopenharmony_ci bool color_in_use = false; 203bf215546Sopenharmony_ci for (auto adj : adjecency) { 204bf215546Sopenharmony_ci if (live_ranges[adj].m_color == color) { 205bf215546Sopenharmony_ci color_in_use = true; 206bf215546Sopenharmony_ci break; 207bf215546Sopenharmony_ci } 208bf215546Sopenharmony_ci } 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci if (color_in_use) { 211bf215546Sopenharmony_ci ++color; 212bf215546Sopenharmony_ci continue; 213bf215546Sopenharmony_ci } 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci r.m_color = color; 216bf215546Sopenharmony_ci break; 217bf215546Sopenharmony_ci } 218bf215546Sopenharmony_ci if (color == 124) 219bf215546Sopenharmony_ci return false; 220bf215546Sopenharmony_ci } 221bf215546Sopenharmony_ci } 222bf215546Sopenharmony_ci return true; 223bf215546Sopenharmony_ci} 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_cibool register_allocation(LiveRangeMap& lrm) 226bf215546Sopenharmony_ci{ 227bf215546Sopenharmony_ci Interference interference(lrm); 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci std::map<int, Group> groups; 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci // setup fixed colors and group relationships 232bf215546Sopenharmony_ci for (int i = 0; i < 4; ++i) { 233bf215546Sopenharmony_ci auto& comp = lrm.component(i); 234bf215546Sopenharmony_ci for (auto& entry : comp) { 235bf215546Sopenharmony_ci sfn_log << SfnLog::merge << "Prepare RA for " 236bf215546Sopenharmony_ci << *entry.m_register 237bf215546Sopenharmony_ci << " [" << entry.m_start << ", " << entry.m_end << "]\n"; 238bf215546Sopenharmony_ci auto pin = entry.m_register->pin(); 239bf215546Sopenharmony_ci if (entry.m_start == -1 && entry.m_end == -1) { 240bf215546Sopenharmony_ci if (pin == pin_group || pin == pin_chgr) 241bf215546Sopenharmony_ci entry.m_register->set_chan(7); 242bf215546Sopenharmony_ci continue; 243bf215546Sopenharmony_ci } 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci auto sel = entry.m_register->sel(); 246bf215546Sopenharmony_ci /* fully pinned registers contain system values with the 247bf215546Sopenharmony_ci * definite register index, and array values are allocated 248bf215546Sopenharmony_ci * right after the system registers, so just reuse the IDs (for now) */ 249bf215546Sopenharmony_ci if (pin == pin_fully || pin == pin_array) { 250bf215546Sopenharmony_ci /* Must set all array element entries */ 251bf215546Sopenharmony_ci sfn_log << SfnLog::merge << "Pin color " << sel << " to " << *entry.m_register << "\n"; 252bf215546Sopenharmony_ci entry.m_color = sel; 253bf215546Sopenharmony_ci } else if (pin == pin_group || pin == pin_chgr) { 254bf215546Sopenharmony_ci /* Groups must all have the same sel() value, because they are used 255bf215546Sopenharmony_ci * as vec4 registers */ 256bf215546Sopenharmony_ci auto igroup = groups.find(sel); 257bf215546Sopenharmony_ci if (igroup != groups.end()) { 258bf215546Sopenharmony_ci igroup->second.channels[i] = entry.m_register; 259bf215546Sopenharmony_ci assert(comp[entry.m_register->index()].m_register->index() == entry.m_register->index()); 260bf215546Sopenharmony_ci } else { 261bf215546Sopenharmony_ci int priority = entry.m_use.test(LiveRangeEntry::use_export) ? - entry.m_end : entry.m_start; 262bf215546Sopenharmony_ci Group group{priority, {nullptr, nullptr, nullptr, nullptr}}; 263bf215546Sopenharmony_ci group.channels[i] = entry.m_register; 264bf215546Sopenharmony_ci assert(comp[group.channels[i]->index()].m_register->index() == entry.m_register->index()); 265bf215546Sopenharmony_ci groups[sel] = group; 266bf215546Sopenharmony_ci } 267bf215546Sopenharmony_ci } 268bf215546Sopenharmony_ci } 269bf215546Sopenharmony_ci } 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci GroupRegisters groups_sorted; 272bf215546Sopenharmony_ci for (auto& [sel, group] : groups) 273bf215546Sopenharmony_ci groups_sorted.push(group); 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci if (!group_allocation (lrm, interference, groups_sorted)) 276bf215546Sopenharmony_ci return false; 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci if (!scalar_allocation(lrm, interference)) 279bf215546Sopenharmony_ci return false; 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci for (int i = 0; i < 4; ++i) { 282bf215546Sopenharmony_ci auto& comp = lrm.component(i); 283bf215546Sopenharmony_ci for (auto& entry : comp) { 284bf215546Sopenharmony_ci sfn_log << SfnLog::merge << "Set " << *entry.m_register << " to "; 285bf215546Sopenharmony_ci entry.m_register->set_sel(entry.m_color); 286bf215546Sopenharmony_ci entry.m_register->set_pin(pin_none); 287bf215546Sopenharmony_ci sfn_log << SfnLog::merge << *entry.m_register << "\n"; 288bf215546Sopenharmony_ci } 289bf215546Sopenharmony_ci } 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci return true; 292bf215546Sopenharmony_ci} 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ci} 295