• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &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(
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