xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/r600/sfn/sfn_liverangeevaluator.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 &reg, 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