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