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