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 &reg, 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