• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mesa-c++  -*-
2  *
3  * Copyright (c) 2021 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_instr_alugroup.h"
28 #include "sfn_instr_export.h"
29 #include "sfn_instr_fetch.h"
30 #include "sfn_instr_mem.h"
31 #include "sfn_instr_lds.h"
32 #include "sfn_instr_tex.h"
33 #include "sfn_instr_controlflow.h"
34 
35 #include <iostream>
36 #include <sstream>
37 #include <numeric>
38 
39 namespace r600 {
40 
41 using std::string;
42 using std::vector;
43 
Instr()44 Instr::Instr():
45    m_use_count(0),
46    m_block_id(std::numeric_limits<int>::max()),
47    m_index(std::numeric_limits<int>::max())
48 {
49 }
50 
~Instr()51 Instr::~Instr()
52 {
53 
54 }
55 
print(std::ostream & os) const56 void Instr::print(std::ostream& os) const
57 {
58    do_print(os);
59 }
60 
ready() const61 bool Instr::ready() const
62 {
63    for (auto& i : m_required_instr)
64       if (!i->ready())
65          return false;
66    return do_ready();
67 }
68 
int_from_string_with_prefix(const std::string & str,const std::string & prefix)69 int int_from_string_with_prefix(const std::string& str, const std::string& prefix)
70 {
71    if (str.substr(0, prefix.length()) != prefix) {
72       std::cerr << "Expect '" << prefix << "' as start of '" << str << "'\n";
73       assert(0);
74    }
75 
76    std::stringstream help(str.substr(prefix.length()));
77    int retval;
78    help >> retval;
79    return retval;
80 }
81 
sel_and_szw_from_string(const std::string & str,RegisterVec4::Swizzle & swz,bool & is_ssa)82 int sel_and_szw_from_string(const std::string& str, RegisterVec4::Swizzle &swz, bool& is_ssa)
83 {
84    assert(str[0] == 'R' || str[0] == '_' || str[0] == 'S');
85    int sel = 0;
86 
87    auto istr = str.begin() + 1;
88 
89    if (str[0] == '_') {
90       while (istr != str.end() && *istr == '_')
91          ++istr;
92       sel = std::numeric_limits<int>::max();
93    } else {
94       while (istr != str.end() && isdigit(*istr)) {
95          sel *= 10;
96          sel += *istr - '0';
97          ++istr;
98       }
99    }
100 
101    assert(*istr == '.');
102    istr++;
103 
104    int i = 0;
105    while (istr != str.end()) {
106       switch (*istr) {
107       case 'x': swz[i] = 0; break;
108       case 'y': swz[i] = 1; break;
109       case 'z': swz[i] = 2; break;
110       case 'w': swz[i] = 3; break;
111       case '0': swz[i] = 4; break;
112       case '1': swz[i] = 5; break;
113       case '_': swz[i] = 7; break;
114       default:
115          unreachable("Unknown swizzle character");
116       }
117       ++istr;
118       ++i;
119    }
120 
121    is_ssa = str[0] == 'S';
122 
123    return sel;
124 }
125 
is_last() const126 bool Instr::is_last() const
127 {
128    return true;
129 }
130 
set_dead()131 bool Instr::set_dead()
132 {
133    if (m_instr_flags.test(always_keep))
134       return false;
135    bool is_dead = propagate_death();
136    m_instr_flags.set(dead);
137    return is_dead;
138 }
139 
propagate_death()140 bool Instr::propagate_death()
141 {
142    return true;
143 }
144 
replace_source(PRegister old_src,PVirtualValue new_src)145 bool Instr::replace_source(PRegister old_src, PVirtualValue new_src)
146 {
147    (void)old_src;
148    (void)new_src;
149    return false;
150 }
151 
add_required_instr(Instr * instr)152 void Instr::add_required_instr(Instr *instr)
153 {
154    assert(instr);
155    m_required_instr.push_back(instr);
156    instr->m_dependend_instr.push_back(this);
157 }
158 
replace_required_instr(Instr * old_instr,Instr * new_instr)159 void Instr::replace_required_instr(Instr *old_instr, Instr *new_instr)
160 {
161 
162    for (auto i = m_required_instr.begin(); i != m_required_instr.end(); ++i) {
163       if (*i == old_instr)
164          *i = new_instr;
165    }
166 }
167 
replace_dest(PRegister new_dest,r600::AluInstr * move_instr)168 bool Instr::replace_dest(PRegister new_dest, r600::AluInstr *move_instr)
169 {
170    (void)new_dest;
171    (void)move_instr;
172    return false;
173 }
174 
set_blockid(int id,int index)175 void Instr::set_blockid(int id, int index)
176 {
177    m_block_id = id;
178    m_index = index;
179    forward_set_blockid(id, index);
180 }
181 
182 
forward_set_blockid(int id,int index)183 void Instr::forward_set_blockid(int id, int index)
184 {
185    (void)id;
186    (void)index;
187 }
188 
InstrWithVectorResult(const RegisterVec4 & dest,const RegisterVec4::Swizzle & dest_swizzle)189 InstrWithVectorResult::InstrWithVectorResult(const RegisterVec4& dest,
190                                              const RegisterVec4::Swizzle& dest_swizzle):
191    m_dest(dest),
192    m_dest_swizzle(dest_swizzle)
193 {
194    for (int i = 0; i < 4; ++i) {
195       if (m_dest_swizzle[i] < 6)
196          m_dest[i]->add_parent(this);
197    }
198 }
199 
print_dest(std::ostream & os) const200 void InstrWithVectorResult::print_dest(std::ostream& os) const
201 {
202    os << (m_dest[0]->is_ssa() ? 'S' : 'R' ) << m_dest.sel();
203    os << ".";
204    for (int i = 0; i < 4; ++i)
205       os << VirtualValue::chanchar[m_dest_swizzle[i]];
206 }
207 
comp_dest(const RegisterVec4 & dest,const RegisterVec4::Swizzle & dest_swizzle) const208 bool InstrWithVectorResult::comp_dest(const RegisterVec4& dest,
209                                       const RegisterVec4::Swizzle& dest_swizzle) const
210 {
211    for(int i = 0; i < 4; ++i) {
212       if (!m_dest[i]->equal_to(*dest[i])) {
213          return false;
214       }
215       if (m_dest_swizzle[i] != dest_swizzle[i])
216          return false;
217    }
218    return true;
219 }
220 
do_print(std::ostream & os) const221 void Block::do_print(std::ostream& os) const
222 {
223    for (int j = 0; j < 2 * m_nesting_depth; ++j)
224       os << ' ';
225    os << "BLOCK START\n";
226    for (auto& i : m_instructions) {
227       for (int j = 0; j < 2 * (m_nesting_depth + i->nesting_corr()) + 2; ++j)
228          os << ' ';
229       os << *i << "\n";
230    }
231    for (int j = 0; j < 2 * m_nesting_depth; ++j)
232       os << ' ';
233    os << "BLOCK END\n";
234 }
235 
is_equal_to(const Block & lhs) const236 bool Block::is_equal_to(const Block& lhs) const
237 {
238    if (m_id != lhs.m_id || m_nesting_depth != lhs.m_nesting_depth)
239       return false;
240 
241    if (m_instructions.size() != lhs.m_instructions.size())
242       return false;
243 
244    return std::inner_product(m_instructions.begin(), m_instructions.end(), lhs.m_instructions.begin(),
245                              true,
246                              [] (bool l, bool r) { return l && r;},
247    [](PInst l, PInst r) { return l->equal_to(*r);});
248 }
249 
operator !=(const Block & lhs,const Block & rhs)250 inline bool operator != (const Block& lhs, const Block& rhs)
251 {
252    return !lhs.is_equal_to(rhs);
253 }
254 
erase(iterator node)255 void Block::erase(iterator node)
256 {
257    m_instructions.erase(node);
258 }
259 
set_type(Type t)260 void Block::set_type(Type t)
261 {
262    m_blocK_type = t;
263    switch (t) {
264    case vtx:
265    case gds:
266    case tex: m_remaining_slots = 8; break; /* TODO: 16 for >= EVERGREEN */
267    default:
268       m_remaining_slots = 0xffff;
269    }
270 }
271 
Block(int nesting_depth,int id)272 Block::Block(int nesting_depth, int id):
273    m_nesting_depth(nesting_depth),
274    m_id(id),
275    m_next_index(0)
276 {
277    assert(!has_instr_flag(force_cf));
278 }
279 
accept(ConstInstrVisitor & visitor) const280 void Block::accept(ConstInstrVisitor& visitor) const
281 {
282    visitor.visit(*this);
283 }
284 
accept(InstrVisitor & visitor)285 void Block::accept(InstrVisitor& visitor)
286 {
287    visitor.visit(this);
288 }
289 
push_back(PInst instr)290 void Block::push_back(PInst instr)
291 {
292    instr->set_blockid(m_id, m_next_index++);
293    if (m_remaining_slots != 0xffff) {
294       uint32_t new_slots = instr->slots();
295       m_remaining_slots -= new_slots;
296    }
297    if (m_lds_group_start)
298       m_lds_group_requirement += instr->slots();
299 
300    m_instructions.push_back(instr);
301 }
302 
try_reserve_kcache(const AluGroup & group)303 bool Block::try_reserve_kcache(const AluGroup& group)
304 {
305    auto kcache = m_kcache;
306 
307    auto kcache_constants = group.get_kconsts();
308    for (auto& kc : kcache_constants)  {
309       auto u = kc->as_uniform();
310       assert(u);
311       if (!try_reserve_kcache(*u, kcache)) {
312          m_kcache_alloc_failed = true;
313          return false;
314       }
315    }
316 
317    m_kcache = kcache;
318    m_kcache_alloc_failed = false;
319    return true;
320 }
321 
try_reserve_kcache(const AluInstr & instr)322 bool Block::try_reserve_kcache(const AluInstr& instr)
323 {
324    auto kcache = m_kcache;
325 
326    for (auto& src : instr.sources()) {
327       auto u = src->as_uniform();
328       if (u) {
329          if (!try_reserve_kcache(*u, kcache)) {
330             m_kcache_alloc_failed = true;
331             return false;
332          }
333       }
334    }
335    m_kcache = kcache;
336    m_kcache_alloc_failed = false;
337    return true;
338 }
339 
set_chipclass(r600_chip_class chip_class)340 void Block::set_chipclass(r600_chip_class chip_class)
341 {
342    if (chip_class < ISA_CC_EVERGREEN)
343       s_max_kcache_banks = 2;
344    else
345       s_max_kcache_banks = 4;
346 }
347 
348 unsigned Block::s_max_kcache_banks = 4;
349 
try_reserve_kcache(const UniformValue & u,std::array<KCacheLine,4> & kcache) const350 bool Block::try_reserve_kcache(const UniformValue& u,
351                                std::array<KCacheLine, 4>& kcache) const
352 {
353    const int kcache_banks = s_max_kcache_banks; // TODO: handle pre-evergreen
354 
355    int bank = u.kcache_bank();
356    int sel  = (u.sel() - 512);
357    int line = sel >> 4;
358 
359    bool found = false;
360 
361    for (int i = 0; i < kcache_banks && !found; ++i) {
362       if (kcache[i].mode) {
363          if (kcache[i].bank < bank)
364             continue;
365 
366          if ((kcache[i].bank == bank &&
367               kcache[i].addr > line  + 1) ||
368              kcache[i].bank > bank) {
369             if (kcache[kcache_banks - 1].mode)
370                return false;
371 
372             memmove(&kcache[i+1],&kcache[i], (kcache_banks-i-1)*sizeof(KCacheLine));
373             kcache[i].mode = KCacheLine::lock_1;
374             kcache[i].bank = bank;
375             kcache[i].addr = line;
376             return true;
377          }
378 
379          int d = line - kcache[i].addr;
380 
381          if (d == -1) {
382             kcache[i].addr--;
383             if (kcache[i].mode == KCacheLine::lock_2) {
384                /* we are prepending the line to the current set,
385                 * discarding the existing second line,
386                 * so we'll have to insert line+2 after it */
387                line += 2;
388                continue;
389             } else if (kcache[i].mode == KCacheLine::lock_1) {
390                kcache[i].mode = KCacheLine::lock_2;
391                return true;
392             } else {
393                /* V_SQ_CF_KCACHE_LOCK_LOOP_INDEX is not supported */
394                return false;
395             }
396          } else if (d == 1) {
397             kcache[i].mode = KCacheLine::lock_2;
398             return true;
399          } else if (d == 0) {
400             return true;
401          }
402       } else { /* free kcache set - use it */
403          kcache[i].mode = KCacheLine::lock_1;
404          kcache[i].bank = bank;
405          kcache[i].addr = line;
406          return true;
407       }
408    }
409    return false;
410 }
411 
lds_group_start(AluInstr * alu)412 void Block::lds_group_start(AluInstr *alu)
413 {
414    assert(!m_lds_group_start);
415    m_lds_group_start = alu;
416    m_lds_group_requirement = 0;
417 }
418 
lds_group_end()419 void Block::lds_group_end()
420 {
421    assert(m_lds_group_start);
422    m_lds_group_start->set_required_slots(m_lds_group_requirement);
423    m_lds_group_start = 0;
424 }
425 
InstrWithVectorResult(const InstrWithVectorResult & orig)426 InstrWithVectorResult::InstrWithVectorResult(const InstrWithVectorResult& orig):
427    m_dest(orig.m_dest),
428    m_dest_swizzle(orig.m_dest_swizzle)
429 {
430 }
431 
432 class InstrComparer : public ConstInstrVisitor {
433 public:
434    InstrComparer() = default;
435    bool result {false};
436 
437 #define DECLARE_MEMBER(TYPE)         \
438     InstrComparer(const TYPE *instr) \
439     {                                \
440        this_ ## TYPE = instr;        \
441     }                                \
442                                      \
443     void visit(const TYPE& instr)    \
444     {                                \
445        result = false;               \
446        if (!this_ ## TYPE)           \
447          return;                     \
448       result = this_ ## TYPE->is_equal_to(instr); \
449    }                                 \
450                                      \
451    const TYPE *this_ ## TYPE{nullptr};
452 
453    DECLARE_MEMBER(AluInstr);
454    DECLARE_MEMBER(AluGroup);
455    DECLARE_MEMBER(TexInstr);
456    DECLARE_MEMBER(ExportInstr);
457    DECLARE_MEMBER(FetchInstr);
458    DECLARE_MEMBER(Block);
459    DECLARE_MEMBER(ControlFlowInstr);
460    DECLARE_MEMBER(IfInstr);
461    DECLARE_MEMBER(ScratchIOInstr);
462    DECLARE_MEMBER(StreamOutInstr);
463    DECLARE_MEMBER(MemRingOutInstr);
464    DECLARE_MEMBER(EmitVertexInstr);
465    DECLARE_MEMBER(GDSInstr);
466    DECLARE_MEMBER(WriteTFInstr);
467    DECLARE_MEMBER(LDSAtomicInstr);
468    DECLARE_MEMBER(LDSReadInstr);
469    DECLARE_MEMBER(RatInstr);
470 };
471 
472 class InstrCompareForward: public ConstInstrVisitor {
473 public:
474 
visit(const AluInstr & instr)475    void visit(const AluInstr& instr) override {
476       m_comparer = InstrComparer(&instr);
477    }
478 
visit(const AluGroup & instr)479    void visit(const AluGroup& instr) override {
480       m_comparer = InstrComparer(&instr);
481    }
482 
visit(const TexInstr & instr)483    void visit(const TexInstr& instr) override {
484       m_comparer = InstrComparer(&instr);
485    }
486 
visit(const ExportInstr & instr)487    void visit(const ExportInstr& instr) override {
488       m_comparer = InstrComparer(&instr);
489    }
490 
visit(const FetchInstr & instr)491    void visit(const FetchInstr& instr) override {
492       m_comparer = InstrComparer(&instr);
493    }
494 
visit(const Block & instr)495    void visit(const Block& instr) override {
496       m_comparer = InstrComparer(&instr);
497    }
498 
visit(const ControlFlowInstr & instr)499    void visit(const ControlFlowInstr& instr) override {
500       m_comparer = InstrComparer(&instr);
501    }
502 
visit(const IfInstr & instr)503    void visit(const IfInstr& instr) override {
504       m_comparer = InstrComparer(&instr);
505    }
506 
visit(const ScratchIOInstr & instr)507    void visit(const ScratchIOInstr& instr) override {
508       m_comparer = InstrComparer(&instr);
509    }
510 
visit(const StreamOutInstr & instr)511    void visit(const StreamOutInstr& instr) override {
512       m_comparer = InstrComparer(&instr);
513    }
514 
visit(const MemRingOutInstr & instr)515    void visit(const MemRingOutInstr& instr) override {
516       m_comparer = InstrComparer(&instr);
517    }
518 
visit(const EmitVertexInstr & instr)519    void visit(const EmitVertexInstr& instr) override {
520       m_comparer = InstrComparer(&instr);
521    }
522 
visit(const GDSInstr & instr)523    void visit(const GDSInstr& instr) override {
524       m_comparer = InstrComparer(&instr);
525    }
526 
visit(const WriteTFInstr & instr)527    void visit(const WriteTFInstr& instr) override {
528       m_comparer = InstrComparer(&instr);
529    }
530 
visit(const LDSAtomicInstr & instr)531    void visit(const LDSAtomicInstr& instr) override {
532       m_comparer = InstrComparer(&instr);
533    }
534 
visit(const LDSReadInstr & instr)535    void visit(const LDSReadInstr& instr) override {
536          m_comparer = InstrComparer(&instr);
537    }
538 
visit(const RatInstr & instr)539    void visit(const RatInstr& instr) override {
540          m_comparer = InstrComparer(&instr);
541    }
542 
543    InstrComparer m_comparer;
544 };
545 
546 
equal_to(const Instr & lhs) const547 bool Instr::equal_to(const Instr& lhs) const
548 {
549    InstrCompareForward cmp;
550    accept(cmp);
551    lhs.accept(cmp.m_comparer);
552 
553    return cmp.m_comparer.result;
554 }
555 
556 
557 
558 
559 } // ns r600
560