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