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_liverangeevaluator.h"
28 #include "sfn_liverangeevaluator_helpers.h"
29
30 #include "sfn_instr_alugroup.h"
31 #include "sfn_instr_controlflow.h"
32 #include "sfn_instr_export.h"
33 #include "sfn_instr_fetch.h"
34 #include "sfn_instr_mem.h"
35 #include "sfn_instr_tex.h"
36 #include "sfn_shader.h"
37 #include "sfn_debug.h"
38
39 #include <algorithm>
40 #include <map>
41
42 namespace r600 {
43
44 class LiveRangeInstrVisitor : public InstrVisitor {
45 public:
46 LiveRangeInstrVisitor(LiveRangeMap& live_range_map);
47
48 void visit(AluInstr *instr) override;
49 void visit(AluGroup *instr) override;
50 void visit(TexInstr *instr) override;
51 void visit(ExportInstr *instr) override;
52 void visit(FetchInstr *instr) override;
53 void visit(Block *instr) override;
54 void visit(ControlFlowInstr *instr) override;
55 void visit(IfInstr *instr) override;
56 void visit(ScratchIOInstr *instr) override;
57 void visit(StreamOutInstr *instr) override;
58 void visit(MemRingOutInstr *instr) override;
59 void visit(EmitVertexInstr *instr) override {(void)instr;}
60 void visit(GDSInstr *instr) override;
61 void visit(WriteTFInstr *instr) override;
62 void visit(LDSAtomicInstr *instr) override;
63 void visit(LDSReadInstr *instr) override;
64 void visit(RatInstr *instr) override;
65
66 void finalize();
67 private:
68
69 void record_write(const Register *reg);
70 void record_read(const Register *reg, LiveRangeEntry::EUse use);
71
72 void record_write(const RegisterVec4& reg, const RegisterVec4::Swizzle& swizzle);
73 void record_read(const RegisterVec4 ®, LiveRangeEntry::EUse use);
74
75 void scope_if();
76 void scope_else();
77 void scope_endif();
78 void scope_loop_begin();
79 void scope_loop_end();
80 void scope_loop_break();
81 ProgramScope *create_scope(ProgramScope *parent, ProgramScopeType type,
82 int id, int nesting_depth, int line);
83
84 std::vector<std::unique_ptr<ProgramScope>> m_scopes;
85 ProgramScope *m_current_scope;
86 LiveRangeMap& m_live_range_map;
87 RegisterAccess m_register_access;
88
89 int m_line{0};
90 int m_if_id{1};
91 int m_loop_id{1};
92 };
93
LiveRangeEvaluator()94 LiveRangeEvaluator::LiveRangeEvaluator()
95 {
96
97 }
98
99
run(Shader& sh)100 LiveRangeMap LiveRangeEvaluator::run(Shader& sh)
101 {
102
103 LiveRangeMap range_map = sh.prepare_live_range_map();
104
105
106 LiveRangeInstrVisitor evaluator(range_map);
107
108 for (auto& b : sh.func())
109 b->accept(evaluator);
110
111 evaluator.finalize();
112
113 return range_map;
114 }
115
finalize()116 void LiveRangeInstrVisitor::finalize()
117 {
118 m_current_scope->set_end(m_line);
119
120 for (int i = 0; i < 4; ++i) {
121
122 auto& live_ranges = m_live_range_map.component(i);
123 for(const auto& r : live_ranges) {
124 if (r.m_register->live_end_pinned())
125 record_read(r.m_register, LiveRangeEntry::use_unspecified);
126 }
127
128 auto& comp_access = m_register_access.component(i);
129
130 for (size_t i = 0; i < comp_access.size(); ++i) {
131 sfn_log << SfnLog::merge << "Evaluae access for " << *live_ranges[i].m_register << "\n";
132
133 auto& rca = comp_access[i];
134 rca.update_required_live_range();
135 live_ranges[i].m_start = rca.range().start;
136 live_ranges[i].m_end = rca.range().end;
137 live_ranges[i].m_use = rca.use_type();
138 }
139 }
140 }
141
LiveRangeInstrVisitor(LiveRangeMap& live_range_map)142 LiveRangeInstrVisitor::LiveRangeInstrVisitor(LiveRangeMap& live_range_map):
143 m_live_range_map(live_range_map),
144 m_register_access(live_range_map.sizes())
145 {
146 if (sfn_log.has_debug_flag(SfnLog::merge)) {
147 sfn_log << SfnLog::merge << "Have component register numbers: ";
148 for (auto n : live_range_map.sizes())
149 sfn_log << n << " ";
150 sfn_log << "\n";
151 }
152
153 m_scopes.push_back(std::make_unique<ProgramScope>(nullptr, outer_scope, 0, 0, 0));
154 m_current_scope = m_scopes[0].get();
155
156 for (int i = 0; i < 4; ++i) {
157 const auto& comp = live_range_map.component(i);
158 for(const auto& r : comp) {
159 if (r.m_register->live_start_pinned())
160 record_write(r.m_register);
161 }
162 }
163 m_line = 1;
164 }
165
record_write(const RegisterVec4& reg, const RegisterVec4::Swizzle &swizzle)166 void LiveRangeInstrVisitor::record_write(const RegisterVec4& reg, const RegisterVec4::Swizzle &swizzle)
167 {
168 for (int i = 0; i < 4; ++i) {
169 if (swizzle[i] < 6 && reg[i]->chan() < 4)
170 record_write(reg[i]);
171 }
172 }
173
record_read(const RegisterVec4& reg, LiveRangeEntry::EUse use)174 void LiveRangeInstrVisitor::record_read(const RegisterVec4& reg, LiveRangeEntry::EUse use)
175 {
176 for (int i = 0; i < 4; ++i) {
177 if (reg[i]->chan() < 4)
178 record_read(reg[i], use);
179 }
180 }
181
scope_if()182 void LiveRangeInstrVisitor::scope_if()
183 {
184 m_current_scope = create_scope(m_current_scope, if_branch, m_if_id++,
185 m_current_scope->nesting_depth() + 1, m_line + 1);
186 }
187
scope_else()188 void LiveRangeInstrVisitor::scope_else()
189 {
190 assert(m_current_scope->type() == if_branch);
191 m_current_scope->set_end(m_line - 1);
192
193 m_current_scope = create_scope(m_current_scope->parent(), else_branch, m_current_scope->id(),
194 m_current_scope->nesting_depth() + 1, m_line + 1);
195 }
196
scope_endif()197 void LiveRangeInstrVisitor::scope_endif()
198 {
199 m_current_scope->set_end(m_line - 1);
200 m_current_scope = m_current_scope->parent();
201 assert(m_current_scope);
202 }
203
scope_loop_begin()204 void LiveRangeInstrVisitor::scope_loop_begin()
205 {
206 m_current_scope = create_scope(m_current_scope, loop_body, m_loop_id++,
207 m_current_scope->nesting_depth() + 1, m_line);
208 }
209
scope_loop_end()210 void LiveRangeInstrVisitor::scope_loop_end()
211 {
212 m_current_scope->set_end(m_line);
213 m_current_scope = m_current_scope->parent();
214 assert(m_current_scope);
215 }
216
scope_loop_break()217 void LiveRangeInstrVisitor::scope_loop_break()
218 {
219 m_current_scope->set_loop_break_line(m_line);
220 }
221
create_scope(ProgramScope *parent, ProgramScopeType type, int id, int nesting_depth, int line)222 ProgramScope *LiveRangeInstrVisitor::create_scope(ProgramScope *parent, ProgramScopeType type,
223 int id, int nesting_depth, int line)
224 {
225 m_scopes.emplace_back(std::make_unique<ProgramScope>(parent, type, id, nesting_depth, line));
226 return m_scopes[m_scopes.size() - 1].get();
227 }
228
visit(AluInstr *instr)229 void LiveRangeInstrVisitor::visit(AluInstr *instr)
230 {
231 sfn_log << SfnLog::merge << "Visit " << *instr << "\n";
232 if (instr->has_alu_flag(alu_write))
233 record_write(instr->dest());
234 for (unsigned i = 0; i < instr->n_sources(); ++i) {
235 record_read(instr->src(i).as_register(), LiveRangeEntry::use_unspecified);
236 auto uniform = instr->src(i).as_uniform();
237 if (uniform && uniform->buf_addr()) {
238 record_read(uniform->buf_addr()->as_register(), LiveRangeEntry::use_unspecified);
239 }
240 }
241 }
242
visit(AluGroup *group)243 void LiveRangeInstrVisitor::visit(AluGroup *group)
244 {
245 for (auto i : *group)
246 if (i)
247 i->accept(*this);
248 }
249
visit(TexInstr *instr)250 void LiveRangeInstrVisitor::visit(TexInstr *instr)
251 {
252 sfn_log << SfnLog::merge << "Visit " << *instr << "\n";
253 record_write(instr->dst(), instr->all_dest_swizzle());
254
255 auto src = instr->src();
256 record_read(src, LiveRangeEntry::use_unspecified);
257
258 if (instr->sampler_offset() && instr->sampler_offset()->as_register())
259 record_read(instr->sampler_offset()->as_register(), LiveRangeEntry::use_unspecified);
260
261 }
262
visit(ExportInstr *instr)263 void LiveRangeInstrVisitor::visit(ExportInstr *instr)
264 {
265 sfn_log << SfnLog::merge << "Visit " << *instr << "\n";
266 auto src = instr->value();
267 record_read(src, LiveRangeEntry::use_export);
268 }
269
visit(FetchInstr *instr)270 void LiveRangeInstrVisitor::visit(FetchInstr *instr)
271 {
272 sfn_log << SfnLog::merge << "Visit " << *instr << "\n";
273 record_write(instr->dst(), instr->all_dest_swizzle());
274 auto& src = instr->src();
275 if (src.chan() < 4) /* Channel can be 7 to disable source */
276 record_read(&src, LiveRangeEntry::use_unspecified);
277 }
278
visit(Block *instr)279 void LiveRangeInstrVisitor::visit(Block *instr)
280 {
281 sfn_log << SfnLog::merge << "Visit block\n";
282 for (auto i : *instr) {
283 i->accept(*this);
284 if (i->end_group())
285 ++m_line;
286 }
287 sfn_log << SfnLog::merge << "End block\n";
288 }
289
visit(ScratchIOInstr *instr)290 void LiveRangeInstrVisitor::visit(ScratchIOInstr *instr)
291 {
292 auto& src = instr->value();
293 for (int i = 0; i < 4; ++i) {
294 if ((1 << i) & instr->write_mask()) {
295 if (instr->is_read())
296 record_write(src[i]);
297 else
298 record_read(src[i], LiveRangeEntry::use_unspecified);
299 }
300 }
301
302 auto addr = instr->address();
303 if (addr)
304 record_read(addr, LiveRangeEntry::use_unspecified);
305 }
306
visit(StreamOutInstr *instr)307 void LiveRangeInstrVisitor::visit(StreamOutInstr *instr)
308 {
309 sfn_log << SfnLog::merge << "Visit " << *instr << "\n";
310 auto src = instr->value();
311 record_read(src, LiveRangeEntry::use_unspecified);
312 }
313
visit(MemRingOutInstr *instr)314 void LiveRangeInstrVisitor::visit(MemRingOutInstr *instr)
315 {
316 sfn_log << SfnLog::merge << "Visit " << *instr << "\n";
317 auto src = instr->value();
318 record_read(src, LiveRangeEntry::use_unspecified);
319
320 auto idx = instr->export_index();
321 if (idx && idx->as_register())
322 record_read(idx->as_register(), LiveRangeEntry::use_unspecified);
323 }
324
visit(ControlFlowInstr *instr)325 void LiveRangeInstrVisitor::visit(ControlFlowInstr *instr)
326 {
327 switch (instr->cf_type()) {
328 case ControlFlowInstr::cf_else: scope_else(); break;
329 case ControlFlowInstr::cf_endif: scope_endif(); break;
330 case ControlFlowInstr::cf_loop_begin: scope_loop_begin(); break;
331 case ControlFlowInstr::cf_loop_end: scope_loop_end(); break;
332 case ControlFlowInstr::cf_loop_break: scope_loop_break(); break;
333 case ControlFlowInstr::cf_loop_continue: break;
334 case ControlFlowInstr::cf_wait_ack: break;
335 default:
336 unreachable("Flow control unreachanble");
337 }
338 }
339
visit(IfInstr *instr)340 void LiveRangeInstrVisitor::visit(IfInstr *instr)
341 {
342 instr->predicate()->accept(*this);
343 scope_if();
344 }
345
visit(GDSInstr *instr)346 void LiveRangeInstrVisitor::visit(GDSInstr *instr)
347 {
348 sfn_log << SfnLog::merge << "Visit " << *instr << "\n";
349 record_read(instr->src(), LiveRangeEntry::use_unspecified);
350 if (instr->uav_id())
351 record_read(instr->uav_id(), LiveRangeEntry::use_unspecified);
352 record_write(instr->dest());
353 }
354
visit(RatInstr *instr)355 void LiveRangeInstrVisitor::visit(RatInstr *instr)
356 {
357 sfn_log << SfnLog::merge << "Visit " << *instr << "\n";
358 record_read(instr->value(), LiveRangeEntry::use_unspecified);
359 record_read(instr->addr(), LiveRangeEntry::use_unspecified);
360
361 auto idx = instr->rat_id_offset();
362 if (idx)
363 record_read(idx, LiveRangeEntry::use_unspecified);
364 }
365
366
visit(WriteTFInstr *instr)367 void LiveRangeInstrVisitor::visit(WriteTFInstr *instr)
368 {
369 record_read(instr->value(), LiveRangeEntry::use_export);
370 }
371
visit(UNUSED LDSAtomicInstr *instr)372 void LiveRangeInstrVisitor::visit(UNUSED LDSAtomicInstr *instr)
373 {
374 unreachable("LDSAtomicInstr must be lowered before scheduling and live range evaluation");
375 }
376
visit(UNUSED LDSReadInstr *instr)377 void LiveRangeInstrVisitor::visit(UNUSED LDSReadInstr *instr)
378 {
379 unreachable("LDSReadInstr must be lowered before scheduling and live range evaluation");
380 }
381
record_write(const Register *reg)382 void LiveRangeInstrVisitor::record_write(const Register *reg)
383 {
384 auto addr = reg->get_addr();
385 if (addr && addr->as_register()) {
386 record_read(addr->as_register(), LiveRangeEntry::use_unspecified);
387
388 const auto av = static_cast<const LocalArrayValue *>(reg);
389 auto& array = av->array();
390
391 sfn_log << SfnLog::merge << array << " write:" << m_line << "\n";
392
393 for (auto i = 0u; i < array.size(); ++i) {
394 auto& rav = m_register_access(array(i, reg->chan()));
395 rav.record_write(m_line, m_current_scope);
396 }
397 } else {
398 auto& ra = m_register_access(*reg);
399 sfn_log << SfnLog::merge << *reg << " write:" << m_line << "\n";
400 ra.record_write(m_line, m_current_scope);
401 }
402 }
403
record_read(const Register *reg, LiveRangeEntry::EUse use)404 void LiveRangeInstrVisitor::record_read(const Register *reg, LiveRangeEntry::EUse use)
405 {
406 if (!reg)
407 return;
408
409 auto addr = reg->get_addr();
410 if (addr && addr->as_register()) {
411 sfn_log << SfnLog::merge << "Record reading address register " << *addr << "\n";
412
413 auto& ra = m_register_access(*addr->as_register());
414 ra.record_read(m_line, m_current_scope, use);
415
416 const auto av = static_cast<const LocalArrayValue *>(reg);
417 auto& array = av->array();
418 sfn_log << SfnLog::merge << array << " read:" << m_line << "\n";
419
420 for (auto i = 0u; i < array.size(); ++i) {
421 auto& rav = m_register_access(array(i, reg->chan()));
422 rav.record_read(m_line, m_current_scope, use);
423 }
424 } else {
425 sfn_log << SfnLog::merge << *reg << " read:" << m_line << "\n";
426 auto& ra = m_register_access(*reg);
427 ra.record_read(m_line, m_current_scope, use);
428 }
429 }
430
operator <<(std::ostream& os, const LiveRangeMap& lrm)431 std::ostream& operator << (std::ostream& os, const LiveRangeMap& lrm)
432 {
433 os << "Live ranges\n";
434 for (int i = 0; i < 4; ++i) {
435 const auto& comp = lrm.component(i);
436 for (auto& range : comp)
437 os << " " << range << "\n";
438 }
439 return os;
440 }
441
operator ==(const LiveRangeMap& lhs, const LiveRangeMap& rhs)442 bool operator == (const LiveRangeMap& lhs, const LiveRangeMap& rhs)
443 {
444 for (int i = 0; i < 4; ++i) {
445 const auto& lc = lhs.component(i);
446 const auto& rc = rhs.component(i);
447 if (lc.size() != rc.size())
448 return false;
449
450 for (auto j = 0u; j < lc.size(); ++j) {
451 const auto& lv = lc[j];
452 const auto& rv = rc[j];
453
454 if (lv.m_start != rv.m_start ||
455 lv.m_end != rv.m_end ||
456 lv.m_color != rv.m_color ||
457 !lv.m_register->equal_to(*rv.m_register))
458 return false;
459 }
460 }
461
462 return true;
463 }
464
465
466 }
467
468