• 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_virtualvalues.h"
28 #include "sfn_alu_defines.h"
29 #include "sfn_valuefactory.h"
30 #include "sfn_instr.h"
31 #include "sfn_debug.h"
32 
33 #include "util/macros.h"
34 
35 #include <ostream>
36 #include <iostream>
37 #include <iomanip>
38 #include <limits>
39 #include <sstream>
40 
41 namespace r600 {
42 
operator <<(std::ostream & os,Pin pin)43 std::ostream& operator << (std::ostream& os, Pin pin)
44 {
45 #define PRINT_PIN(X) case pin_ ## X : os << #X; break
46    switch (pin) {
47    PRINT_PIN(chan);
48    PRINT_PIN(array);
49    PRINT_PIN(fully);
50    PRINT_PIN(group);
51    PRINT_PIN(chgr);
52    PRINT_PIN(free);
53    case pin_none:
54    default:
55       ;
56    }
57 #undef PRINT_PIN
58    return os;
59 }
60 
VirtualValue(int sel,int chan,Pin pin)61 VirtualValue::VirtualValue(int sel, int chan, Pin pin):
62    m_sel(sel), m_chan(chan), m_pins(pin)
63 {
64 #if __cpp_exceptions >= 199711L
65    ASSERT_OR_THROW(m_sel < virtual_register_base || pin != pin_fully, "Register is virtual but pinned to sel");
66 #endif
67 }
68 
ready(int block,int index) const69 bool VirtualValue::ready(int block, int index) const
70 {
71    (void)block;
72    (void)index;
73    return true;
74 }
75 
is_virtual() const76 bool VirtualValue::is_virtual() const
77 {
78    return m_sel >= virtual_register_base;
79 }
80 
81 class ValueComparer: public ConstRegisterVisitor {
82 public:
83    ValueComparer();
84    ValueComparer(const Register *value);
85    ValueComparer(const LocalArray *value);
86    ValueComparer(const LocalArrayValue *value);
87    ValueComparer(const UniformValue *value);
88    ValueComparer(const LiteralConstant *value);
89    ValueComparer(const InlineConstant *value);
90 
91    void visit(const Register& other) override;
92    void visit(const LocalArray& other) override;
93    void visit(const LocalArrayValue& other) override;
94    void visit(const UniformValue& value) override;
95    void visit(const LiteralConstant& other) override;
96    void visit(const InlineConstant& other) override;
97 
98    bool m_result;
99 private:
100    const Register *m_register;
101    const LocalArray *m_array;
102    const LocalArrayValue *m_array_value;
103    const UniformValue *m_uniform_value;
104    const LiteralConstant *m_literal_value;
105    const InlineConstant *m_inline_constant;
106 };
107 
108 class ValueCompareCreater: public ConstRegisterVisitor {
109 public:
visit(const Register & value)110    void visit(const Register& value) { compare = ValueComparer(&value);}
visit(const LocalArray & value)111    void visit(const LocalArray& value) {compare = ValueComparer(&value);}
visit(const LocalArrayValue & value)112    void visit(const LocalArrayValue& value) {compare = ValueComparer(&value);}
visit(const UniformValue & value)113    void visit(const UniformValue& value) {compare = ValueComparer(&value);}
visit(const LiteralConstant & value)114    void visit(const LiteralConstant& value) {compare = ValueComparer(&value);}
visit(const InlineConstant & value)115    void visit(const InlineConstant& value) {compare = ValueComparer(&value);}
116 
117    ValueComparer compare;
118 };
119 
from_string(const std::string & s)120 VirtualValue::Pointer VirtualValue::from_string(const std::string& s)
121 {
122    switch (s[0]) {
123    case 'S':
124    case 'R': return Register::from_string(s);
125    case 'L': return LiteralConstant::from_string(s);
126    case 'K': return UniformValue::from_string(s);
127    case 'P': return InlineConstant::param_from_string(s);
128    case 'I': return InlineConstant::from_string(s);
129 
130    default:
131       std::cerr << "'" << s << "'";
132       unreachable("Unknown register type");
133    }
134 }
135 
equal_to(const VirtualValue & other) const136 bool VirtualValue::equal_to(const VirtualValue& other) const
137 {
138    bool result = m_sel == other.m_sel &&
139          m_chan == other.m_chan &&
140          m_pins == other.m_pins;
141 
142    if (result) {
143       ValueCompareCreater comp_creater;
144       accept(comp_creater);
145       other.accept(comp_creater.compare);
146       result &= comp_creater.compare.m_result;
147    }
148 
149    return result;
150 }
151 
get_addr() const152 VirtualValue::Pointer VirtualValue::get_addr() const
153 {
154    class GetAddressRegister: public ConstRegisterVisitor {
155    public:
156       void visit(const VirtualValue& value) {(void)value;}
157       void visit(const Register& value) {(void)value;};
158       void visit(const LocalArray& value) {(void)value;}
159       void visit(const LocalArrayValue& value) {m_result = value.addr();}
160       void visit(const UniformValue& value) {(void)value;}
161       void visit(const LiteralConstant& value) {(void)value;}
162       void visit(const InlineConstant& value) {(void)value;}
163 
164       GetAddressRegister() : m_result(nullptr) {}
165 
166       PVirtualValue m_result;
167    };
168    GetAddressRegister get_addr;
169    accept(get_addr);
170    return get_addr.m_result;
171 }
172 
Register(int sel,int chan,Pin pin)173 Register::Register(int sel, int chan, Pin pin):
174    VirtualValue(sel, chan, pin)
175 {
176 }
177 
add_parent(Instr * instr)178 void Register::add_parent(Instr *instr)
179 {
180    m_parents.insert(instr);
181    instr->add_use();
182    add_parent_to_array(instr);
183 }
184 
add_parent_to_array(Instr * instr)185 void Register::add_parent_to_array(Instr *instr)
186 {
187    (void)instr;
188 }
189 
del_parent(Instr * instr)190 void Register::del_parent(Instr *instr)
191 {
192    m_parents.erase(instr);
193    instr->dec_use();
194    del_parent_from_array(instr);
195 }
196 
del_parent_from_array(Instr * instr)197 void Register::del_parent_from_array(Instr *instr)
198 {
199    (void)instr;
200 }
201 
202 
add_use(Instr * instr)203 void Register::add_use(Instr *instr)
204 {
205    const auto& [itr, inserted] = m_uses.insert(instr);  {}
206 
207    if (inserted) {
208       for (auto& p: m_parents)
209          p->add_use();
210    }
211 }
212 
del_use(Instr * instr)213 void Register::del_use(Instr *instr)
214 {
215    sfn_log << SfnLog::opt << "Del use of " << *this << " in " << *instr << "\n";
216    if (m_uses.find(instr) != m_uses.end()) {
217       m_uses.erase(instr);
218       if (is_ssa())
219          for (auto& p: m_parents)
220             p->dec_use();
221    }
222 }
223 
ready(int block,int index) const224 bool Register::ready(int block, int index) const
225 {
226    for (auto p : m_parents) {
227       if (p->block_id() <= block) {
228          if (p->index() < index && !p->is_scheduled()) {
229             return false;
230          }
231       }
232    }
233    return true;
234 }
235 
accept(RegisterVisitor & visitor)236 void Register::accept(RegisterVisitor& visitor)
237 {
238    visitor.visit(*this);
239 }
240 
accept(ConstRegisterVisitor & visitor) const241 void Register::accept(ConstRegisterVisitor& visitor) const
242 {
243    visitor.visit(*this);
244 }
245 
246 
pin_live_range(bool start,bool end)247 void Register::pin_live_range(bool start, bool end)
248 {
249    m_pin_start = start;
250    m_pin_end = end;
251 }
252 
set_is_ssa(bool value)253 void Register::set_is_ssa(bool value)
254 {
255    m_is_ssa = value;
256 }
257 
print(std::ostream & os) const258 void Register::print(std::ostream& os) const
259 {
260    os << (m_is_ssa ? "S" : "R") << sel() << "." << chanchar[chan()];
261 
262    if (pin() !=  pin_none)
263       os << "@" << pin();
264 }
265 
from_string(const std::string & s)266 Register::Pointer Register::from_string(const std::string &s)
267 {
268    std::string numstr;
269    char chan = 0;
270    std::string pinstr;
271 
272    assert(s[0] == 'R' || s[0] == '_' || s[0] == 'S' );
273 
274    int type = 0;
275    for (unsigned i = 1; i < s.length(); ++i) {
276       if (s[i] == '.') {
277          type = 1;
278          continue;
279       } else if (s[i] == '@') {
280          type = 2;
281          continue;
282       }
283 
284       switch (type) {
285       case 0: numstr.append(1, s[i]); break;
286       case 1: chan = s[i]; break;
287       case 2: pinstr.append(1, s[i]); break;
288       default:
289          unreachable("Malformed register string");
290       }
291    }
292 
293    int sel;
294    if (s[0] != '_') {
295       std::istringstream n(numstr);
296       n >> sel;
297    } else {
298       sel = std::numeric_limits<int>::max();
299    }
300 
301    auto p = pin_none;
302    if (pinstr == "chan")
303       p = pin_chan;
304    else if (pinstr == "array")
305       p = pin_array;
306    else if (pinstr == "fully")
307       p = pin_fully;
308    else if (pinstr == "group")
309       p = pin_group;
310    else if (pinstr == "chgr")
311       p = pin_chgr;
312    else if (pinstr == "free")
313       p = pin_free;
314 
315    switch (chan) {
316    case 'x' : chan = 0; break;
317    case 'y' : chan = 1; break;
318    case 'z' : chan = 2; break;
319    case 'w' : chan = 3; break;
320    case '0' : chan = 4; break;
321    case '1' : chan = 5; break;
322    case '_' : chan = 7; break;
323    }
324 
325    auto reg = new Register( sel, chan, p);
326    reg->set_is_ssa(s[0] == 'S');
327    if (p == pin_fully || p == pin_array)
328       reg->pin_live_range(true);
329    return reg;
330 }
331 
RegisterVec4()332 RegisterVec4::RegisterVec4():
333    m_sel(-1),
334    m_swz({7,7,7,7}),
335    m_values({nullptr, nullptr, nullptr, nullptr})
336 {
337 }
338 
RegisterVec4(int sel,bool is_ssa,const Swizzle & swz,Pin pin)339 RegisterVec4::RegisterVec4(int sel, bool is_ssa, const Swizzle& swz, Pin pin):
340    m_sel(sel),
341    m_swz(swz)
342 {
343    for (int i = 0; i < 4; ++i) {
344       m_values[i] = new Element( *this, new Register(m_sel, swz[i], pin));
345       m_values[i]->value()->set_is_ssa(is_ssa);
346    }
347 }
348 
RegisterVec4(const RegisterVec4 & orig)349 RegisterVec4::RegisterVec4(const RegisterVec4& orig):
350    m_sel(orig.m_sel),
351    m_swz(orig.m_swz)
352 {
353    for (int i = 0; i < 4; ++i)
354       m_values[i] = new Element(*this, orig.m_values[i]->value());
355 }
356 
RegisterVec4(PRegister x,PRegister y,PRegister z,PRegister w,Pin pin)357 RegisterVec4::RegisterVec4(PRegister x, PRegister y, PRegister z, PRegister w, Pin pin)
358 {
359    PRegister dummy = nullptr;
360 
361    if (x) {
362       m_sel = x->sel();
363    } else if (y) {
364       m_sel = y->sel();
365    } else if (z) {
366       m_sel = z->sel();
367    } else if (w) {
368       m_sel = w->sel();
369    } else
370       m_sel = 0;
371 
372    if (!(x && y && z && w))
373       dummy = new Register (m_sel, 7, pin_none);
374 
375    m_values[0] = new Element(*this,  x ? x : dummy);
376    m_values[1] = new Element(*this,  y ? y : dummy);
377    m_values[2] = new Element(*this,  z ? z : dummy);
378    m_values[3] = new Element(*this,  w ? w : dummy);
379 
380    for (int i = 0; i < 4; ++i) {
381       if (m_values[0]->value()->pin() == pin_fully) {
382          pin = pin_fully;
383          break;
384       }
385    }
386 
387    for (int i = 0; i < 4; ++i) {
388       switch (m_values[i]->value()->pin()) {
389       case pin_none:
390       case pin_free:
391          m_values[i]->value()->set_pin(pin);
392       break;
393       case pin_chan:
394          if (pin == pin_group)
395             m_values[i]->value()->set_pin(pin_chgr);
396       break;
397       default:
398          ;
399       }
400 
401       m_swz[i] = m_values[i]->value()->chan();
402       assert(m_values[i]->value()->sel() == m_sel);
403    }
404 }
405 
add_use(Instr * instr)406 void RegisterVec4::add_use(Instr *instr)
407 {
408    for (auto& r: m_values) {
409       if (r->value()->chan() < 4)
410           r->value()->add_use(instr);
411    }
412 }
413 
del_use(Instr * instr)414 void RegisterVec4::del_use(Instr *instr)
415 {
416    for (auto& r: m_values) {
417       r->value()->del_use(instr);
418    }
419 }
420 
has_uses() const421 bool RegisterVec4::has_uses() const
422 {
423    for (auto& r: m_values) {
424       if (r->value()->has_uses())
425          return true;
426    }
427    return false;
428 }
429 
430 
sel() const431 int RegisterVec4::sel() const
432 {
433    int comp = 0;
434    while (comp < 4 && m_values[comp]->value()->chan() > 3)
435       ++comp;
436    return comp < 4 ? m_values[comp]->value()->sel() : 0;
437 }
438 
ready(int block_id,int index) const439 bool RegisterVec4::ready(int block_id, int index) const
440 {
441    for (int i = 0; i < 4; ++i) {
442       if (m_values[i]->value()->chan() < 4) {
443          if (!m_values[i]->value()->ready(block_id, index))
444             return false;
445       }
446    }
447    return true;
448 }
449 
print(std::ostream & os) const450 void RegisterVec4::print(std::ostream& os) const
451 {
452    os << (m_values[0]->value()->is_ssa() ? 'S' : 'R') << sel() << ".";
453    for (int i = 0; i < 4; ++i)
454       os << VirtualValue::chanchar[m_swz[i]];
455 }
456 
operator ==(const RegisterVec4 & lhs,const RegisterVec4 & rhs)457 bool operator == (const RegisterVec4& lhs, const RegisterVec4& rhs)
458 {
459    for (int i = 0; i < 4; ++i) {
460       assert(lhs[i]);
461       assert(rhs[i]);
462       if (!lhs[i]->equal_to(*rhs[i])) {
463          return false;
464       }
465    }
466    return true;
467 }
468 
Element(const RegisterVec4 & parent,int chan)469 RegisterVec4::Element::Element(const RegisterVec4& parent, int chan):
470    m_parent(parent),
471    m_value(new Register(parent.m_sel, chan, pin_none))
472 {
473 }
474 
Element(const RegisterVec4 & parent,PRegister value)475 RegisterVec4::Element::Element(const RegisterVec4& parent, PRegister value):
476    m_parent(parent),
477    m_value(value)
478 {
479 }
480 
LiteralConstant(uint32_t value)481 LiteralConstant::LiteralConstant(uint32_t value):
482    VirtualValue(ALU_SRC_LITERAL, -1, pin_none),
483    m_value(value)
484 {
485 }
486 
accept(RegisterVisitor & vistor)487 void LiteralConstant::accept(RegisterVisitor& vistor)
488 {
489    vistor.visit(*this);
490 }
491 
accept(ConstRegisterVisitor & vistor) const492 void LiteralConstant::accept(ConstRegisterVisitor& vistor) const
493 {
494    vistor.visit(*this);
495 }
496 
print(std::ostream & os) const497 void LiteralConstant::print(std::ostream& os) const
498 {
499    os << "L[0x" << std::hex << m_value << std::dec << "]";
500 }
501 
from_string(const std::string & s)502 LiteralConstant::Pointer LiteralConstant::from_string(const std::string& s)
503 {
504    if (s[1] != '[')
505       return nullptr;
506 
507    std::string numstr;
508    for (unsigned i = 2; i < s.length(); ++i) {
509       if (s[i] == ']')
510          break;
511 
512       if (isxdigit(s[i]))
513          numstr.append(1, s[i]);
514       if (s[i] == 'x')
515          continue;
516    }
517 
518    std::istringstream n(numstr);
519 
520    uint32_t num;
521    n >> std::hex >> num;
522    return new LiteralConstant( num);
523 }
524 
525 
526 // Inline constants usually don't care about the channel but
527 // ALU_SRC_PV should be pinned, but we only emit these constants
528 // very late, and based on the real register they replace
InlineConstant(int sel,int chan)529 InlineConstant::InlineConstant(int sel, int chan):
530    VirtualValue(sel, chan, pin_none)
531 {
532 }
533 
accept(RegisterVisitor & vistor)534 void InlineConstant::accept(RegisterVisitor& vistor)
535 {
536    vistor.visit(*this);
537 }
538 
accept(ConstRegisterVisitor & vistor) const539 void InlineConstant::accept(ConstRegisterVisitor& vistor) const
540 {
541    vistor.visit(*this);
542 }
543 
print(std::ostream & os) const544 void InlineConstant::print(std::ostream& os) const
545 {
546    auto ivalue = alu_src_const.find(static_cast<AluInlineConstants>(sel()));
547    if (ivalue != alu_src_const.end()) {
548       os << "I[" << ivalue->second.descr<< "]";
549       if (ivalue->second.use_chan)
550          os << "." << chanchar[chan()];
551    } else if (sel() >= ALU_SRC_PARAM_BASE &&
552               sel() <  ALU_SRC_PARAM_BASE + 32 ) {
553       os << "Param"
554           << sel() - ALU_SRC_PARAM_BASE
555           << "." << chanchar[chan()];
556    } else {
557       unreachable("Unknown inline constant");
558    }
559 }
560 
561 std::map<std::string, std::pair<AluInlineConstants, bool>> InlineConstant::s_opmap;
562 
from_string(const std::string & s)563 InlineConstant::Pointer InlineConstant::from_string(const std::string& s)
564 {
565    std::string namestr;
566    char chan = 0;
567 
568    ASSERT_OR_THROW(s[1] == '[', "inline const not started with '['");
569 
570    unsigned i = 2;
571    while (i < s.length()) {
572       if (s[i] == ']')
573          break;
574       namestr.append(1, s[i]);
575       ++i;
576    }
577 
578    ASSERT_OR_THROW(s[i] == ']', "inline const not closed with ']'");
579 
580    auto entry = s_opmap.find(namestr);
581    AluInlineConstants value = ALU_SRC_UNKNOWN;
582    bool use_chan = false;
583 
584    if (entry == s_opmap.end())  {
585       for (auto& [opcode, descr] : alu_src_const) {
586          if (namestr == descr.descr) {
587             value = opcode;
588             use_chan = descr.use_chan;
589             s_opmap[namestr] = std::make_pair(opcode, use_chan);
590 
591             break;
592          }
593       }
594    } else {
595       value = entry->second.first;
596       use_chan = entry->second.second;
597    }
598 
599    ASSERT_OR_THROW(value != ALU_SRC_UNKNOWN, "Unknwon inline constant was given");
600 
601    if (use_chan) {
602       ASSERT_OR_THROW(s[i + 1] == '.', "inline const channel not started with '.'");
603       switch (s[i + 2]) {
604       case 'x': chan = 0; break;
605       case 'y': chan = 1; break;
606       case 'z': chan = 2; break;
607       case 'w': chan = 3; break;
608       case '0': chan = 4; break;
609       case '1': chan = 5; break;
610       case '_': chan = 7; break;
611       default:
612          ASSERT_OR_THROW(0, "invalied inline const channel ");
613       }
614    }
615    return new InlineConstant( value, chan);
616 }
617 
param_from_string(const std::string & s)618 InlineConstant::Pointer InlineConstant::param_from_string(const std::string& s)
619 {
620    assert(s.substr(0, 5) == "Param");
621 
622    int param = 0;
623    int i = 5;
624    while (isdigit(s[i])) {
625       param *= 10;
626       param +=  s[i] - '0';
627       ++i;
628    }
629 
630    int chan = 7;
631    assert(s[i] == '.');
632    switch (s[i+1]) {
633    case 'x': chan = 0; break;
634    case 'y': chan = 1; break;
635    case 'z': chan = 2; break;
636    case 'w': chan = 3; break;
637    default:
638       unreachable("unsupported channel char");
639    }
640 
641    return new InlineConstant( ALU_SRC_PARAM_BASE + param, chan);
642 }
643 
UniformValue(int sel,int chan,int kcache_bank)644 UniformValue::UniformValue(int sel, int chan, int kcache_bank):
645    VirtualValue(sel, chan, pin_none),
646    m_kcache_bank(kcache_bank),
647    m_buf_addr(nullptr)
648 {
649 }
650 
UniformValue(int sel,int chan,PVirtualValue buf_addr)651 UniformValue::UniformValue(int sel, int chan, PVirtualValue buf_addr):
652    VirtualValue(sel, chan, pin_none),
653    m_kcache_bank(0),
654    m_buf_addr(buf_addr)
655 {
656 }
657 
accept(RegisterVisitor & vistor)658 void UniformValue::accept(RegisterVisitor& vistor)
659 {
660    vistor.visit(*this);
661 }
662 
accept(ConstRegisterVisitor & vistor) const663 void UniformValue::accept(ConstRegisterVisitor& vistor) const
664 {
665    vistor.visit(*this);
666 }
667 
buf_addr() const668 PVirtualValue UniformValue::buf_addr() const
669 {
670    return m_buf_addr;
671 }
672 
print(std::ostream & os) const673 void UniformValue::print(std::ostream& os) const
674 {
675    os << "KC" << m_kcache_bank;
676    if (m_buf_addr) {
677       os << "[" << *m_buf_addr
678          << "]";
679    }
680    os << "[" << (sel() - 512) << "]." << chanchar[chan()];
681 }
682 
equal_buf_and_cache(const UniformValue & other) const683 bool UniformValue::equal_buf_and_cache(const UniformValue& other) const
684 {
685    bool result = m_kcache_bank == other.m_kcache_bank;
686    if (result) {
687       if (m_buf_addr && other.m_buf_addr) {
688          result = m_buf_addr->equal_to(other);
689       } else {
690          result = !m_buf_addr && !other.m_buf_addr;
691       }
692    }
693    return result;
694 }
695 
696 
from_string(const std::string & s)697 UniformValue::Pointer UniformValue::from_string(const std::string& s)
698 {
699    assert(s[1] == 'C');
700    std::istringstream is(s.substr(2));
701    int bank;
702    char c;
703    is >> bank;
704    is >> c;
705 
706    assert(c == '[');
707 
708    int index;
709    is >> index;
710 
711    is >> c;
712    assert(c == ']');
713    is >> c;
714    assert(c == '.');
715 
716    is >> c;
717    int chan = 0;
718    switch (c) {
719    case 'x': chan = 0; break;
720    case 'y': chan = 1; break;
721    case 'z': chan = 2; break;
722    case 'w': chan = 3; break;
723    default:
724       unreachable("Unknown channle when reading uniform");
725    }
726    return new UniformValue(index + 512, chan, bank);
727 }
728 
LocalArray(int base_sel,int nchannels,int size,int frac)729 LocalArray::LocalArray(int base_sel, int nchannels, int size, int frac):
730    Register(base_sel, nchannels, pin_array),
731    m_base_sel(base_sel),
732    m_nchannels(nchannels),
733    m_size(size),
734    m_values(size * nchannels),
735    m_frac(frac)
736 {
737    assert(nchannels <= 4);
738    assert(nchannels + frac <= 4);
739 
740    sfn_log << SfnLog::reg << "Allocate array A" <<  base_sel << "("
741            << size << ", " << frac << ", " << nchannels << ")\n";
742 
743    for (int c = 0; c < nchannels; ++c) {
744       for (unsigned i = 0; i < m_size; ++i) {
745          PRegister reg = new Register( base_sel + i, c + frac, pin_array);
746          m_values[m_size * c + i] = new LocalArrayValue(reg, *this);
747 
748          /* Pin the array register on the start, because currently we don't
749           * don't track the first write to an array element as write to all
750           * array elements, and it seems that the one can not just use registers
751           * that are not written to in an array for other purpouses */
752          m_values[m_size * c + i]->pin_live_range(true);
753       }
754    }
755 }
756 
accept(RegisterVisitor & vistor)757 void LocalArray::accept(RegisterVisitor& vistor)
758 {
759    vistor.visit(*this);
760 }
761 
accept(ConstRegisterVisitor & vistor) const762 void LocalArray::accept(ConstRegisterVisitor& vistor) const
763 {
764    vistor.visit(*this);
765 }
766 
print(std::ostream & os) const767 void LocalArray::print(std::ostream& os) const
768 {
769    os << "A" << m_base_sel << "[0 " << ":" << m_values.size() << "].";
770    for (unsigned i = 0; i < m_nchannels; ++i) {
771       os << chanchar[i];
772    }
773 }
774 
775 
size() const776 size_t LocalArray::size() const
777 {
778    return m_size;
779 }
780 
nchannels() const781 uint32_t LocalArray::nchannels() const
782 {
783    return m_nchannels;
784 }
785 
element(size_t offset,PVirtualValue indirect,uint32_t chan)786 PRegister LocalArray::element(size_t offset, PVirtualValue indirect, uint32_t chan)
787 {
788    ASSERT_OR_THROW(offset < m_size, "Array: index out of range");
789    ASSERT_OR_THROW(chan < m_nchannels, "Array: channel out of range");
790 
791    sfn_log << SfnLog::reg << "Request element A" << m_base_sel << "["  << offset;
792    if (indirect)
793       sfn_log   << "+" << *indirect;
794    sfn_log << SfnLog::reg << "]\n";
795 
796    if (indirect) {
797       class ResolveDirectArrayElement: public ConstRegisterVisitor {
798       public:
799          void visit(const Register& value) {(void) value;};
800          void visit(const LocalArray& value) {(void)value; unreachable("An array can't be used as address");}
801          void visit(const LocalArrayValue& value) {(void) value;}
802          void visit(const UniformValue& value) {(void)value;}
803          void visit(const LiteralConstant& value) {offset = value.value(); is_contant = true;}
804          void visit(const InlineConstant& value) {(void)value;}
805 
806          ResolveDirectArrayElement(): offset(0), is_contant(false) {}
807 
808          int offset;
809          bool is_contant;
810       } addr;
811 
812       // If the address os a literal constant then update the offset
813       // and don't access the value indirectly
814       indirect->accept(addr);
815       if (addr.is_contant) {
816          offset += addr.offset;
817          indirect = nullptr;
818          ASSERT_OR_THROW(offset < m_size, "Array: indirect constant index out of range");
819       }
820    }
821 
822    LocalArrayValue *reg = m_values[m_size * chan + offset];
823    if (indirect) {
824       reg = new LocalArrayValue( reg, indirect, *this);
825       m_values_indirect.push_back(reg);
826    }
827 
828    sfn_log << SfnLog::reg << "  got " << *reg << "\n";
829    return reg;
830 }
831 
ready_for_direct(int block,int index,int chan) const832 bool LocalArray::ready_for_direct(int block, int index, int chan) const
833 {
834    if (!Register::ready(block, index))
835       return false;
836 
837    /* For direct access to an array value we also have to take indirect
838     * writes on the same channels into account */
839    for (LocalArrayValue *e : m_values_indirect) {
840       if (e->chan() == chan && !e->Register::ready(block, index)) {
841          return false;
842       }
843    }
844 
845    return true;
846 }
847 
ready_for_indirect(int block,int index,int chan) const848 bool LocalArray::ready_for_indirect(int block, int index, int chan) const
849 {
850    int offset = (chan - m_frac) * m_size;
851    for (unsigned i = 0; i < m_size; ++i) {
852       if (!m_values[offset + i]->Register::ready(block, index))
853          return false;
854    }
855 
856    return ready_for_direct(block, index, chan);
857 }
858 
859 
LocalArrayValue(PRegister reg,PVirtualValue index,LocalArray & array)860 LocalArrayValue::LocalArrayValue(PRegister reg, PVirtualValue index,
861                                  LocalArray& array):
862    Register(reg->sel(), reg->chan(), pin_array),
863    m_addr(index),
864    m_array(array)
865 {
866 }
867 
operator ()(size_t idx,size_t chan) const868 const Register& LocalArray::operator ()(size_t idx, size_t chan) const
869 {
870    return *m_values[m_size  * (chan - m_frac) + idx];
871 }
872 
LocalArrayValue(PRegister reg,LocalArray & array)873 LocalArrayValue::LocalArrayValue(PRegister reg, LocalArray& array):
874    LocalArrayValue(reg, nullptr, array)
875 {
876 
877 }
878 
879 
addr() const880 PVirtualValue LocalArrayValue::addr() const
881 {
882    return m_addr;
883 }
884 
array() const885 const LocalArray& LocalArrayValue::array() const
886 {
887    return m_array;
888 }
889 
890 
forward_del_use(Instr * instr)891 void LocalArrayValue::forward_del_use(Instr *instr)
892 {
893    if (m_addr && m_addr->as_register())
894       m_addr->as_register()->del_use(instr);
895 }
896 
forward_add_use(Instr * instr)897 void LocalArrayValue::forward_add_use(Instr *instr)
898 {
899    if (m_addr && m_addr->as_register())
900       m_addr->as_register()->add_use(instr);
901 }
902 
accept(RegisterVisitor & vistor)903 void LocalArrayValue::accept(RegisterVisitor& vistor)
904 {
905    vistor.visit(*this);
906 }
907 
accept(ConstRegisterVisitor & vistor) const908 void LocalArrayValue::accept(ConstRegisterVisitor& vistor) const
909 {
910    vistor.visit(*this);
911 }
912 
add_parent_to_array(Instr * instr)913 void LocalArrayValue::add_parent_to_array(Instr *instr)
914 {
915    m_array.add_parent(instr);
916 }
917 
del_parent_from_array(Instr * instr)918 void LocalArrayValue::del_parent_from_array(Instr *instr)
919 {
920    m_array.del_parent(instr);
921 }
922 
print(std::ostream & os) const923 void LocalArrayValue::print(std::ostream& os) const
924 {
925    int offset = sel() - m_array.sel();
926    os << "A" << m_array.sel() << "[";
927    if ( offset > 0 && m_addr)
928       os << offset << "+" << *m_addr;
929    else if (m_addr)
930       os << *m_addr;
931    else
932       os << offset;
933    os << "]." << chanchar[chan()];
934 }
935 
ready(int block,int index) const936 bool LocalArrayValue::ready(int block, int index) const
937 {
938    return m_addr ?
939          (m_array.ready_for_indirect(block, index, chan()) && m_addr->ready(block, index)):
940             m_array.ready_for_direct(block, index, chan());
941 }
942 
ValueComparer()943 ValueComparer::ValueComparer() :
944    m_result(false),
945    m_register(nullptr),
946    m_array(nullptr),
947    m_array_value(nullptr),
948    m_uniform_value(nullptr),
949    m_literal_value(nullptr),
950    m_inline_constant(nullptr)
951 {}
952 
ValueComparer(const Register * value)953 ValueComparer::ValueComparer(const Register *value):
954    m_result(false),
955    m_register(value),
956    m_array(nullptr),
957    m_array_value(nullptr),
958    m_uniform_value(nullptr),
959    m_literal_value(nullptr),
960    m_inline_constant(nullptr)
961 {}
962 
ValueComparer(const LocalArray * value)963 ValueComparer::ValueComparer(const LocalArray *value):
964    m_result(false),
965    m_register(nullptr),
966    m_array(value),
967    m_array_value(nullptr),
968    m_uniform_value(nullptr),
969    m_literal_value(nullptr),
970    m_inline_constant(nullptr)
971 {}
972 
ValueComparer(const LocalArrayValue * value)973 ValueComparer::ValueComparer(const LocalArrayValue *value):
974    m_result(false),
975    m_register(nullptr),
976    m_array(nullptr),
977    m_array_value(value),
978    m_uniform_value(nullptr),
979    m_literal_value(nullptr),
980    m_inline_constant(nullptr)
981 {}
982 
ValueComparer(const UniformValue * value)983 ValueComparer::ValueComparer(const UniformValue *value):
984    m_result(false),
985    m_register(nullptr),
986    m_array(nullptr),
987    m_array_value(nullptr),
988    m_uniform_value(value),
989    m_literal_value(nullptr),
990    m_inline_constant(nullptr)
991 {}
992 
ValueComparer(const LiteralConstant * value)993 ValueComparer::ValueComparer(const LiteralConstant *value):
994    m_result(false),
995    m_register(nullptr),
996    m_array(nullptr),
997    m_array_value(nullptr),
998    m_uniform_value(nullptr),
999    m_literal_value(value),
1000    m_inline_constant(nullptr)
1001 {}
1002 
ValueComparer(const InlineConstant * value)1003 ValueComparer::ValueComparer(const InlineConstant *value):
1004    m_result(false),
1005    m_register(nullptr),
1006    m_array(nullptr),
1007    m_array_value(nullptr),
1008    m_uniform_value(nullptr),
1009    m_literal_value(nullptr),
1010    m_inline_constant(value)
1011 {}
1012 
visit(const Register & other)1013 void ValueComparer::visit(const Register& other)
1014 {
1015    (void)other;
1016    m_result = !!m_register;
1017 };
1018 
visit(const LocalArray & other)1019 void ValueComparer::visit(const LocalArray& other)
1020 {
1021    m_result = false;
1022    if (m_array) {
1023       m_result = m_array->size() == other.size() &&
1024             m_array->nchannels() == other.nchannels();
1025    }
1026 };
1027 
visit(const LocalArrayValue & other)1028 void ValueComparer::visit(const LocalArrayValue& other)
1029 {
1030    m_result = false;
1031    if (m_array_value) {
1032       m_result = m_array_value->array().equal_to(other.array());
1033       if (m_result) {
1034          auto my_addr = m_array_value->addr();
1035          auto other_addr = other.addr();
1036          if (my_addr && other_addr) {
1037             m_result = my_addr->equal_to(*other_addr);
1038          } else {
1039             m_result = !my_addr && !other_addr;
1040          }
1041       }
1042    }
1043 };
1044 
visit(const UniformValue & value)1045 void ValueComparer::visit(const UniformValue& value)
1046 {
1047    m_result = false;
1048    if (m_uniform_value) {
1049       m_result = m_uniform_value->kcache_bank() == value.kcache_bank();
1050       if (m_result) {
1051          auto my_buf_addr = m_uniform_value->buf_addr();
1052          auto other_buf_addr = value.buf_addr();
1053          if (my_buf_addr && other_buf_addr) {
1054             m_result = my_buf_addr->equal_to(*other_buf_addr);
1055          } else {
1056             m_result = !my_buf_addr && !other_buf_addr;
1057          }
1058       }
1059    }
1060 };
1061 
visit(const LiteralConstant & other)1062 void ValueComparer::visit(const LiteralConstant& other)
1063 {
1064    m_result = m_literal_value && (m_literal_value->value() == other.value());
1065 };
1066 
visit(const InlineConstant & other)1067 void ValueComparer::visit(const InlineConstant& other)
1068 {
1069    (void)other;
1070    m_result = !!m_inline_constant;
1071 };
1072 
1073 
1074 } // namespace r600
1075