• 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 
29 #include "sfn_alu_defines.h"
30 #include "sfn_debug.h"
31 #include "sfn_instr.h"
32 #include "sfn_valuefactory.h"
33 #include "util/macros.h"
34 #include "util/u_math.h"
35 
36 #include <iomanip>
37 #include <iostream>
38 #include <limits>
39 #include <ostream>
40 #include <sstream>
41 
42 namespace r600 {
43 
44 std::ostream&
operator <<(std::ostream & os,Pin pin)45 operator<<(std::ostream& os, Pin pin)
46 {
47 #define PRINT_PIN(X)                                                                     \
48    case pin_##X:                                                                         \
49       os << #X;                                                                          \
50       break
51    switch (pin) {
52       PRINT_PIN(chan);
53       PRINT_PIN(array);
54       PRINT_PIN(fully);
55       PRINT_PIN(group);
56       PRINT_PIN(chgr);
57       PRINT_PIN(free);
58    case pin_none:
59    default:;
60    }
61 #undef PRINT_PIN
62    return os;
63 }
64 
VirtualValue(int sel,int chan,Pin pin)65 VirtualValue::VirtualValue(int sel, int chan, Pin pin):
66     m_sel(sel),
67     m_chan(chan),
68     m_pins(pin)
69 {
70 #if __cpp_exceptions >= 199711L
71    ASSERT_OR_THROW(m_sel < virtual_register_base || pin != pin_fully,
72                    "Register is virtual but pinned to sel");
73 #endif
74 }
75 
76 bool
ready(int block,int index) const77 VirtualValue::ready(int block, int index) const
78 {
79    (void)block;
80    (void)index;
81    return true;
82 }
83 
84 bool
is_virtual() const85 VirtualValue::is_virtual() const
86 {
87    return m_sel >= virtual_register_base;
88 }
89 
90 class ValueComparer : public ConstRegisterVisitor {
91 public:
92    ValueComparer();
93    ValueComparer(const Register *value);
94    ValueComparer(const LocalArray *value);
95    ValueComparer(const LocalArrayValue *value);
96    ValueComparer(const UniformValue *value);
97    ValueComparer(const LiteralConstant *value);
98    ValueComparer(const InlineConstant *value);
99 
100    void visit(const Register& other) override;
101    void visit(const LocalArray& other) override;
102    void visit(const LocalArrayValue& other) override;
103    void visit(const UniformValue& value) override;
104    void visit(const LiteralConstant& other) override;
105    void visit(const InlineConstant& other) override;
106 
107    bool m_result;
108 
109 private:
110    const Register *m_register;
111    const LocalArray *m_array;
112    const LocalArrayValue *m_array_value;
113    const UniformValue *m_uniform_value;
114    const LiteralConstant *m_literal_value;
115    const InlineConstant *m_inline_constant;
116 };
117 
118 class ValueCompareCreater : public ConstRegisterVisitor {
119 public:
visit(const Register & value)120    void visit(const Register& value) { compare = ValueComparer(&value); }
visit(const LocalArray & value)121    void visit(const LocalArray& value) { compare = ValueComparer(&value); }
visit(const LocalArrayValue & value)122    void visit(const LocalArrayValue& value) { compare = ValueComparer(&value); }
visit(const UniformValue & value)123    void visit(const UniformValue& value) { compare = ValueComparer(&value); }
visit(const LiteralConstant & value)124    void visit(const LiteralConstant& value) { compare = ValueComparer(&value); }
visit(const InlineConstant & value)125    void visit(const InlineConstant& value) { compare = ValueComparer(&value); }
126 
127    ValueComparer compare;
128 };
129 
130 VirtualValue::Pointer
from_string(const std::string & s)131 VirtualValue::from_string(const std::string& s)
132 {
133    switch (s[0]) {
134    case 'S':
135    case 'R':
136       return Register::from_string(s);
137    case 'L':
138       return LiteralConstant::from_string(s);
139    case 'K':
140       return UniformValue::from_string(s, nullptr);
141    case 'P':
142       return InlineConstant::param_from_string(s);
143    case 'I':
144       return InlineConstant::from_string(s);
145 
146    default:
147       std::cerr << "'" << s << "'";
148       unreachable("Unknown register type");
149    }
150 }
151 
152 bool
equal_to(const VirtualValue & other) const153 VirtualValue::equal_to(const VirtualValue& other) const
154 {
155    bool result = m_sel == other.m_sel && m_chan == other.m_chan && m_pins == other.m_pins;
156 
157    if (result) {
158       ValueCompareCreater comp_creater;
159       accept(comp_creater);
160       other.accept(comp_creater.compare);
161       result &= comp_creater.compare.m_result;
162    }
163 
164    return result;
165 }
166 
167 VirtualValue::Pointer
get_addr() const168 VirtualValue::get_addr() const
169 {
170    class GetAddressRegister : public ConstRegisterVisitor {
171    public:
172       void visit(const VirtualValue& value) { (void)value; }
173       void visit(const Register& value) { (void)value; };
174       void visit(const LocalArray& value) { (void)value; }
175       void visit(const LocalArrayValue& value) { m_result = value.addr(); }
176       void visit(const UniformValue& value) { (void)value; }
177       void visit(const LiteralConstant& value) { (void)value; }
178       void visit(const InlineConstant& value) { (void)value; }
179 
180       GetAddressRegister():
181           m_result(nullptr)
182       {
183       }
184 
185       PVirtualValue m_result;
186    };
187    GetAddressRegister get_addr;
188    accept(get_addr);
189    return get_addr.m_result;
190 }
191 
Register(int sel,int chan,Pin pin)192 Register::Register(int sel, int chan, Pin pin):
193     VirtualValue(sel, chan, pin)
194 {
195 }
196 
197 void
add_parent(Instr * instr)198 Register::add_parent(Instr *instr)
199 {
200    m_parents.insert(instr);
201    add_parent_to_array(instr);
202 }
203 
204 void
add_parent_to_array(Instr * instr)205 Register::add_parent_to_array(Instr *instr)
206 {
207    (void)instr;
208 }
209 
210 void
del_parent(Instr * instr)211 Register::del_parent(Instr *instr)
212 {
213    m_parents.erase(instr);
214    del_parent_from_array(instr);
215 }
216 
217 void
del_parent_from_array(Instr * instr)218 Register::del_parent_from_array(Instr *instr)
219 {
220    (void)instr;
221 }
222 
223 void
add_use(Instr * instr)224 Register::add_use(Instr *instr)
225 {
226    m_uses.insert(instr);
227 }
228 
229 void
del_use(Instr * instr)230 Register::del_use(Instr *instr)
231 {
232    sfn_log << SfnLog::opt << "Del use of " << *this << " in " << *instr << "\n";
233    if (m_uses.find(instr) != m_uses.end()) {
234       m_uses.erase(instr);
235    }
236 }
237 
238 bool
ready(int block,int index) const239 Register::ready(int block, int index) const
240 {
241    for (auto p : m_parents) {
242       if (p->block_id() <= block) {
243          if (p->index() < index && !p->is_scheduled()) {
244             return false;
245          }
246       }
247    }
248    return true;
249 }
250 
251 void
accept(RegisterVisitor & visitor)252 Register::accept(RegisterVisitor& visitor)
253 {
254    visitor.visit(*this);
255 }
256 
257 void
accept(ConstRegisterVisitor & visitor) const258 Register::accept(ConstRegisterVisitor& visitor) const
259 {
260    visitor.visit(*this);
261 }
262 
263 void
print(std::ostream & os) const264 Register::print(std::ostream& os) const
265 {
266    if (m_flags.test(addr_or_idx)) {
267       switch (sel()) {
268       case AddressRegister::addr: os << "AR"; break;
269       case AddressRegister::idx0: os << "IDX0"; break;
270       case AddressRegister::idx1: os << "IDX1"; break;
271       default:
272          unreachable("Wrong address ID");
273       }
274       return;
275    }
276 
277    os << (m_flags.test(ssa) ? "S" : "R") << sel() << "." << chanchar[chan()];
278 
279    if (pin() != pin_none)
280       os << "@" << pin();
281    if (m_flags.any()) {
282       os << "{";
283       if (m_flags.test(ssa))
284          os << "s";
285       if (m_flags.test(pin_start))
286          os << "b";
287       if (m_flags.test(pin_end))
288          os << "e";
289       os << "}";
290    }
291 }
292 
293 Register::Pointer
from_string(const std::string & s)294 Register::from_string(const std::string& s)
295 {
296    std::string numstr;
297    char chan = 0;
298    std::string pinstr;
299 
300    if (s == "AR") {
301       return new AddressRegister(AddressRegister::addr);
302    } else if (s == "IDX0") {
303       return new AddressRegister(AddressRegister::idx0);
304    } else if (s == "IDX1") {
305       return new AddressRegister(AddressRegister::idx1);
306    }
307 
308    assert(s[0] == 'R' || s[0] == '_' || s[0] == 'S');
309 
310    int type = 0;
311    for (unsigned i = 1; i < s.length(); ++i) {
312       if (s[i] == '.') {
313          type = 1;
314          continue;
315       } else if (s[i] == '@') {
316          type = 2;
317          continue;
318       }
319 
320       switch (type) {
321       case 0:
322          numstr.append(1, s[i]);
323          break;
324       case 1:
325          chan = s[i];
326          break;
327       case 2:
328          pinstr.append(1, s[i]);
329          break;
330       default:
331          unreachable("Malformed register string");
332       }
333    }
334 
335    int sel;
336    if (s[0] != '_') {
337       std::istringstream n(numstr);
338       n >> sel;
339    } else {
340       sel = std::numeric_limits<int>::max();
341    }
342 
343    auto p = pin_none;
344    if (pinstr == "chan")
345       p = pin_chan;
346    else if (pinstr == "array")
347       p = pin_array;
348    else if (pinstr == "fully")
349       p = pin_fully;
350    else if (pinstr == "group")
351       p = pin_group;
352    else if (pinstr == "chgr")
353       p = pin_chgr;
354    else if (pinstr == "free")
355       p = pin_free;
356 
357    switch (chan) {
358    case 'x':
359       chan = 0;
360       break;
361    case 'y':
362       chan = 1;
363       break;
364    case 'z':
365       chan = 2;
366       break;
367    case 'w':
368       chan = 3;
369       break;
370    case '0':
371       chan = 4;
372       break;
373    case '1':
374       chan = 5;
375       break;
376    case '_':
377       chan = 7;
378       break;
379    }
380 
381    auto reg = new Register(sel, chan, p);
382    if (s[0] == 'S')
383       reg->set_flag(ssa);
384    if (p == pin_fully || p == pin_array)
385       reg->set_flag(pin_start);
386    return reg;
387 }
388 
RegisterVec4()389 RegisterVec4::RegisterVec4():
390     m_sel(-1),
391     m_swz({7, 7, 7, 7}),
392     m_values({nullptr, nullptr, nullptr, nullptr})
393 {
394 }
395 
RegisterVec4(int sel,bool is_ssa,const Swizzle & swz,Pin pin)396 RegisterVec4::RegisterVec4(int sel, bool is_ssa, const Swizzle& swz, Pin pin):
397     m_sel(sel),
398     m_swz(swz)
399 {
400    for (int i = 0; i < 4; ++i) {
401       m_values[i] = new Element(*this, new Register(m_sel, swz[i], pin));
402       if (is_ssa)
403          m_values[i]->value()->set_flag(Register::ssa);
404    }
405 }
406 
RegisterVec4(const RegisterVec4 & orig)407 RegisterVec4::RegisterVec4(const RegisterVec4& orig):
408     m_sel(orig.m_sel),
409     m_swz(orig.m_swz)
410 {
411    for (int i = 0; i < 4; ++i)
412       m_values[i] = new Element(*this, orig.m_values[i]->value());
413 }
414 
RegisterVec4(PRegister x,PRegister y,PRegister z,PRegister w,Pin pin)415 RegisterVec4::RegisterVec4(PRegister x, PRegister y, PRegister z, PRegister w, Pin pin)
416 {
417    PRegister dummy = nullptr;
418 
419    if (x) {
420       m_sel = x->sel();
421    } else if (y) {
422       m_sel = y->sel();
423    } else if (z) {
424       m_sel = z->sel();
425    } else if (w) {
426       m_sel = w->sel();
427    } else
428       m_sel = 0;
429 
430    if (!(x && y && z && w))
431       dummy = new Register(m_sel, 7, pin_none);
432 
433    m_values[0] = new Element(*this, x ? x : dummy);
434    m_values[1] = new Element(*this, y ? y : dummy);
435    m_values[2] = new Element(*this, z ? z : dummy);
436    m_values[3] = new Element(*this, w ? w : dummy);
437 
438    for (int i = 0; i < 4; ++i) {
439       if (m_values[0]->value()->pin() == pin_fully) {
440          pin = pin_fully;
441          break;
442       }
443    }
444 
445    for (int i = 0; i < 4; ++i) {
446       switch (m_values[i]->value()->pin()) {
447       case pin_none:
448       case pin_free:
449          m_values[i]->value()->set_pin(pin);
450          break;
451       case pin_chan:
452          if (pin == pin_group)
453             m_values[i]->value()->set_pin(pin_chgr);
454          break;
455       default:;
456       }
457 
458       m_swz[i] = m_values[i]->value()->chan();
459       assert(m_values[i]->value()->sel() == m_sel);
460    }
461 }
462 
463 void
add_use(Instr * instr)464 RegisterVec4::add_use(Instr *instr)
465 {
466    for (auto& r : m_values) {
467       if (r->value()->chan() < 4)
468          r->value()->add_use(instr);
469    }
470 }
471 
472 void
del_use(Instr * instr)473 RegisterVec4::del_use(Instr *instr)
474 {
475    for (auto& r : m_values) {
476       r->value()->del_use(instr);
477    }
478 }
479 
480 bool
has_uses() const481 RegisterVec4::has_uses() const
482 {
483    for (auto& r : m_values) {
484       if (r->value()->has_uses())
485          return true;
486    }
487    return false;
488 }
489 
490 int
sel() const491 RegisterVec4::sel() const
492 {
493    int comp = 0;
494    while (comp < 4 && m_values[comp]->value()->chan() > 3)
495       ++comp;
496    return comp < 4 ? m_values[comp]->value()->sel() : 0;
497 }
498 
499 bool
ready(int block_id,int index) const500 RegisterVec4::ready(int block_id, int index) const
501 {
502    for (int i = 0; i < 4; ++i) {
503       if (m_values[i]->value()->chan() < 4) {
504          if (!m_values[i]->value()->ready(block_id, index))
505             return false;
506       }
507    }
508    return true;
509 }
510 
511 void
print(std::ostream & os) const512 RegisterVec4::print(std::ostream& os) const
513 {
514    os << (m_values[0]->value()->has_flag(Register::ssa) ? 'S' : 'R') << sel() << ".";
515    for (int i = 0; i < 4; ++i)
516       os << VirtualValue::chanchar[m_values[i]->value()->chan()];
517 }
518 
519 bool
operator ==(const RegisterVec4 & lhs,const RegisterVec4 & rhs)520 operator==(const RegisterVec4& lhs, const RegisterVec4& rhs)
521 {
522    for (int i = 0; i < 4; ++i) {
523       assert(lhs[i]);
524       assert(rhs[i]);
525       if (!lhs[i]->equal_to(*rhs[i])) {
526          return false;
527       }
528    }
529    return true;
530 }
531 
Element(const RegisterVec4 & parent,int chan)532 RegisterVec4::Element::Element(const RegisterVec4& parent, int chan):
533     m_parent(parent),
534     m_value(new Register(parent.m_sel, chan, pin_none))
535 {
536 }
537 
Element(const RegisterVec4 & parent,PRegister value)538 RegisterVec4::Element::Element(const RegisterVec4& parent, PRegister value):
539     m_parent(parent),
540     m_value(value)
541 {
542 }
543 
LiteralConstant(uint32_t value)544 LiteralConstant::LiteralConstant(uint32_t value):
545     VirtualValue(ALU_SRC_LITERAL, -1, pin_none),
546     m_value(value)
547 {
548 }
549 
550 void
accept(RegisterVisitor & vistor)551 LiteralConstant::accept(RegisterVisitor& vistor)
552 {
553    vistor.visit(*this);
554 }
555 
556 void
accept(ConstRegisterVisitor & vistor) const557 LiteralConstant::accept(ConstRegisterVisitor& vistor) const
558 {
559    vistor.visit(*this);
560 }
561 
562 void
print(std::ostream & os) const563 LiteralConstant::print(std::ostream& os) const
564 {
565    os << "L[0x" << std::hex << m_value << std::dec << "]";
566 }
567 
568 LiteralConstant::Pointer
from_string(const std::string & s)569 LiteralConstant::from_string(const std::string& s)
570 {
571    if (s[1] != '[')
572       return nullptr;
573 
574    std::string numstr;
575    for (unsigned i = 2; i < s.length(); ++i) {
576       if (s[i] == ']')
577          break;
578 
579       if (isxdigit(s[i]))
580          numstr.append(1, s[i]);
581       if (s[i] == 'x')
582          continue;
583    }
584 
585    std::istringstream n(numstr);
586 
587    uint32_t num;
588    n >> std::hex >> num;
589    return new LiteralConstant(num);
590 }
591 
592 // Inline constants usually don't care about the channel but
593 // ALU_SRC_PV should be pinned, but we only emit these constants
594 // very late, and based on the real register they replace
InlineConstant(int sel,int chan)595 InlineConstant::InlineConstant(int sel, int chan):
596     VirtualValue(sel, chan, pin_none)
597 {
598 }
599 
600 void
accept(RegisterVisitor & vistor)601 InlineConstant::accept(RegisterVisitor& vistor)
602 {
603    vistor.visit(*this);
604 }
605 
606 void
accept(ConstRegisterVisitor & vistor) const607 InlineConstant::accept(ConstRegisterVisitor& vistor) const
608 {
609    vistor.visit(*this);
610 }
611 
612 void
print(std::ostream & os) const613 InlineConstant::print(std::ostream& os) const
614 {
615    auto ivalue = alu_src_const.find(static_cast<AluInlineConstants>(sel()));
616    if (ivalue != alu_src_const.end()) {
617       os << "I[" << ivalue->second.descr << "]";
618       if (ivalue->second.use_chan)
619          os << "." << chanchar[chan()];
620    } else if (sel() >= ALU_SRC_PARAM_BASE && sel() < ALU_SRC_PARAM_BASE + 32) {
621       os << "Param" << sel() - ALU_SRC_PARAM_BASE << "." << chanchar[chan()];
622    } else {
623       unreachable("Unknown inline constant");
624    }
625 }
626 
627 std::map<std::string, std::pair<AluInlineConstants, bool>> InlineConstant::s_opmap;
628 
629 InlineConstant::Pointer
from_string(const std::string & s)630 InlineConstant::from_string(const std::string& s)
631 {
632    std::string namestr;
633    char chan = 0;
634 
635    ASSERT_OR_THROW(s[1] == '[', "inline const not started with '['");
636 
637    unsigned i = 2;
638    while (i < s.length()) {
639       if (s[i] == ']')
640          break;
641       namestr.append(1, s[i]);
642       ++i;
643    }
644 
645    ASSERT_OR_THROW(s[i] == ']', "inline const not closed with ']'");
646 
647    auto entry = s_opmap.find(namestr);
648    AluInlineConstants value = ALU_SRC_UNKNOWN;
649    bool use_chan = false;
650 
651    if (entry == s_opmap.end()) {
652       for (auto& [opcode, descr] : alu_src_const) {
653          if (namestr == descr.descr) {
654             value = opcode;
655             use_chan = descr.use_chan;
656             s_opmap[namestr] = std::make_pair(opcode, use_chan);
657 
658             break;
659          }
660       }
661    } else {
662       value = entry->second.first;
663       use_chan = entry->second.second;
664    }
665 
666    ASSERT_OR_THROW(value != ALU_SRC_UNKNOWN, "Unknown inline constant was given");
667 
668    if (use_chan) {
669       ASSERT_OR_THROW(s[i + 1] == '.', "inline const channel not started with '.'");
670       switch (s[i + 2]) {
671       case 'x':
672          chan = 0;
673          break;
674       case 'y':
675          chan = 1;
676          break;
677       case 'z':
678          chan = 2;
679          break;
680       case 'w':
681          chan = 3;
682          break;
683       case '0':
684          chan = 4;
685          break;
686       case '1':
687          chan = 5;
688          break;
689       case '_':
690          chan = 7;
691          break;
692       default:
693          ASSERT_OR_THROW(0, "invalid inline const channel ");
694       }
695    }
696    return new InlineConstant(value, chan);
697 }
698 
699 InlineConstant::Pointer
param_from_string(const std::string & s)700 InlineConstant::param_from_string(const std::string& s)
701 {
702    assert(s.substr(0, 5) == "Param");
703 
704    int param = 0;
705    int i = 5;
706    while (isdigit(s[i])) {
707       param *= 10;
708       param += s[i] - '0';
709       ++i;
710    }
711 
712    int chan = 7;
713    assert(s[i] == '.');
714    switch (s[i + 1]) {
715    case 'x':
716       chan = 0;
717       break;
718    case 'y':
719       chan = 1;
720       break;
721    case 'z':
722       chan = 2;
723       break;
724    case 'w':
725       chan = 3;
726       break;
727    default:
728       unreachable("unsupported channel char");
729    }
730 
731    return new InlineConstant(ALU_SRC_PARAM_BASE + param, chan);
732 }
733 
UniformValue(int sel,int chan,int kcache_bank)734 UniformValue::UniformValue(int sel, int chan, int kcache_bank):
735     VirtualValue(sel, chan, pin_none),
736     m_kcache_bank(kcache_bank),
737     m_buf_addr(nullptr)
738 {
739 }
740 
UniformValue(int sel,int chan,PVirtualValue buf_addr,int kcache_bank)741 UniformValue::UniformValue(int sel, int chan, PVirtualValue buf_addr, int kcache_bank):
742     VirtualValue(sel, chan, pin_none),
743     m_kcache_bank(kcache_bank),
744     m_buf_addr(buf_addr)
745 {
746 }
747 
748 void
accept(RegisterVisitor & vistor)749 UniformValue::accept(RegisterVisitor& vistor)
750 {
751    vistor.visit(*this);
752 }
753 
754 void
accept(ConstRegisterVisitor & vistor) const755 UniformValue::accept(ConstRegisterVisitor& vistor) const
756 {
757    vistor.visit(*this);
758 }
759 
760 PVirtualValue
buf_addr() const761 UniformValue::buf_addr() const
762 {
763    return m_buf_addr;
764 }
765 
set_buf_addr(PVirtualValue addr)766 void UniformValue::set_buf_addr(PVirtualValue addr)
767 {
768    m_buf_addr = addr;
769 }
770 
771 void
print(std::ostream & os) const772 UniformValue::print(std::ostream& os) const
773 {
774    os << "KC" << m_kcache_bank;
775    if (m_buf_addr) {
776       os << "[" << *m_buf_addr << "]";
777    }
778    os << "[" << (sel() - 512) << "]." << chanchar[chan()];
779 }
780 
781 bool
equal_buf_and_cache(const UniformValue & other) const782 UniformValue::equal_buf_and_cache(const UniformValue& other) const
783 {
784    bool result = m_kcache_bank == other.m_kcache_bank;
785    if (result) {
786       if (m_buf_addr && other.m_buf_addr) {
787          result = m_buf_addr->equal_to(other);
788       } else {
789          result = !m_buf_addr && !other.m_buf_addr;
790       }
791    }
792    return result;
793 }
794 
795 UniformValue::Pointer
from_string(const std::string & s,ValueFactory * factory)796 UniformValue::from_string(const std::string& s, ValueFactory *factory)
797 {
798    assert(s[1] == 'C');
799    std::istringstream is(s.substr(2));
800 
801    VirtualValue *bufid = nullptr;
802    int bank;
803    char c;
804    is >> bank;
805    is >> c;
806 
807    assert(c == '[');
808 
809    std::stringstream index0_ss;
810 
811    int index;
812 
813    is >> c;
814    while (c != ']' && is.good()) {
815       index0_ss << c;
816       is >> c;
817    }
818 
819    auto index0_str = index0_ss.str();
820    if (isdigit(index0_str[0])) {
821       std::istringstream is_digit(index0_str);
822       is_digit >> index;
823    } else {
824       bufid = factory ?
825                  factory->src_from_string(index0_str) :
826                  Register::from_string(index0_str);
827       assert(c == ']');
828       is >> c;
829       assert(c == '[');
830       is >> index;
831       is >> c;
832    }
833 
834    assert(c == ']');
835    is >> c;
836    assert(c == '.');
837 
838    is >> c;
839    int chan = 0;
840    switch (c) {
841    case 'x':
842       chan = 0;
843       break;
844    case 'y':
845       chan = 1;
846       break;
847    case 'z':
848       chan = 2;
849       break;
850    case 'w':
851       chan = 3;
852       break;
853    default:
854       unreachable("Unknown channel when reading uniform");
855    }
856    if (bufid)
857       return new UniformValue(index + 512, chan, bufid, bank);
858    else
859       return new UniformValue(index + 512, chan, bank);
860 }
861 
LocalArray(int base_sel,int nchannels,int size,int frac)862 LocalArray::LocalArray(int base_sel, int nchannels, int size, int frac):
863     Register(base_sel, nchannels, pin_array),
864     m_base_sel(base_sel),
865     m_nchannels(nchannels),
866     m_size(size),
867     m_values(size * nchannels),
868     m_frac(frac)
869 {
870    assert(nchannels <= 4);
871    assert(nchannels + frac <= 4);
872 
873    sfn_log << SfnLog::reg << "Allocate array A" << base_sel << "(" << size << ", " << frac
874            << ", " << nchannels << ")\n";
875 
876    auto pin = m_size > 1 ? pin_array : (nchannels > 1 ? pin_none : pin_free);
877    for (int c = 0; c < nchannels; ++c) {
878       for (unsigned i = 0; i < m_size; ++i) {
879          PRegister reg = new Register(base_sel + i, c + frac, pin);
880          m_values[m_size * c + i] = new LocalArrayValue(reg, *this);
881       }
882    }
883 }
884 
885 void
accept(RegisterVisitor & vistor)886 LocalArray::accept(RegisterVisitor& vistor)
887 {
888    vistor.visit(*this);
889 }
890 
891 void
accept(ConstRegisterVisitor & vistor) const892 LocalArray::accept(ConstRegisterVisitor& vistor) const
893 {
894    vistor.visit(*this);
895 }
896 
897 void
print(std::ostream & os) const898 LocalArray::print(std::ostream& os) const
899 {
900    os << "A" << m_base_sel << "[0 "
901       << ":" << m_values.size() << "].";
902    for (unsigned i = 0; i < m_nchannels; ++i) {
903       os << chanchar[i];
904    }
905 }
906 
907 size_t
size() const908 LocalArray::size() const
909 {
910    return m_size;
911 }
912 
913 uint32_t
nchannels() const914 LocalArray::nchannels() const
915 {
916    return m_nchannels;
917 }
918 
919 PRegister
element(size_t offset,PVirtualValue indirect,uint32_t chan)920 LocalArray::element(size_t offset, PVirtualValue indirect, uint32_t chan)
921 {
922    ASSERT_OR_THROW(offset < m_size, "Array: index out of range");
923    ASSERT_OR_THROW(chan < m_nchannels, "Array: channel out of range");
924 
925    sfn_log << SfnLog::reg << "Request element A" << m_base_sel << "[" << offset;
926    if (indirect)
927       sfn_log << "+" << *indirect;
928    sfn_log << SfnLog::reg << "]\n";
929 
930    if (indirect) {
931       class ResolveDirectArrayElement : public ConstRegisterVisitor {
932       public:
933          void visit(const Register& value) { (void)value; };
934          void visit(const LocalArray& value)
935          {
936             (void)value;
937             unreachable("An array can't be used as address");
938          }
939          void visit(const LocalArrayValue& value) { (void)value; }
940          void visit(const UniformValue& value) { (void)value; }
941          void visit(const LiteralConstant& value)
942          {
943             offset = value.value();
944             is_contant = true;
945          }
946          void visit(const InlineConstant& value) { (void)value; }
947 
948          ResolveDirectArrayElement():
949              offset(0),
950              is_contant(false)
951          {
952          }
953 
954          int offset;
955          bool is_contant;
956       } addr;
957 
958       // If the address os a literal constant then update the offset
959       // and don't access the value indirectly
960       indirect->accept(addr);
961       if (addr.is_contant) {
962          offset += addr.offset;
963          indirect = nullptr;
964          ASSERT_OR_THROW(offset < m_size, "Array: indirect constant index out of range");
965       }
966    }
967 
968    LocalArrayValue *reg = m_values[m_size * chan + offset];
969    if (indirect) {
970       reg = new LocalArrayValue(reg, indirect, *this);
971       m_values_indirect.push_back(reg);
972    }
973 
974    sfn_log << SfnLog::reg << "  got " << *reg << "\n";
975    return reg;
976 }
977 
add_parent_to_elements(int chan,Instr * instr)978 void LocalArray::add_parent_to_elements(int chan, Instr *instr)
979 {
980    for (auto& e : m_values)
981       if (e->chan() == chan)
982          e->add_parent(instr);
983 }
984 
985 bool
ready_for_direct(int block,int index,int chan) const986 LocalArray::ready_for_direct(int block, int index, int chan) const
987 {
988    if (!Register::ready(block, index))
989       return false;
990 
991    /* For direct access to an array value we also have to take indirect
992     * writes on the same channels into account */
993    for (LocalArrayValue *e : m_values_indirect) {
994       if (e->chan() == chan && !e->Register::ready(block, index)) {
995          return false;
996       }
997    }
998 
999    return true;
1000 }
1001 
1002 bool
ready_for_indirect(int block,int index,int chan) const1003 LocalArray::ready_for_indirect(int block, int index, int chan) const
1004 {
1005    int offset = (chan - m_frac) * m_size;
1006    for (unsigned i = 0; i < m_size; ++i) {
1007       if (!m_values[offset + i]->Register::ready(block, index))
1008          return false;
1009    }
1010 
1011    return ready_for_direct(block, index, chan);
1012 }
1013 
LocalArrayValue(PRegister reg,PVirtualValue index,LocalArray & array)1014 LocalArrayValue::LocalArrayValue(PRegister reg, PVirtualValue index, LocalArray& array):
1015     Register(reg->sel(), reg->chan(), pin_array),
1016     m_addr(index),
1017     m_array(array)
1018 {
1019 }
1020 
1021 const Register&
operator ()(size_t idx,size_t chan) const1022 LocalArray::operator()(size_t idx, size_t chan) const
1023 {
1024    return *m_values[m_size * (chan - m_frac) + idx];
1025 }
1026 
LocalArrayValue(PRegister reg,LocalArray & array)1027 LocalArrayValue::LocalArrayValue(PRegister reg, LocalArray& array):
1028     LocalArrayValue(reg, nullptr, array)
1029 {
1030 }
1031 
1032 PVirtualValue
addr() const1033 LocalArrayValue::addr() const
1034 {
1035    return m_addr;
1036 }
1037 
set_addr(PRegister addr)1038 void LocalArrayValue::set_addr(PRegister addr)
1039 {
1040    m_addr = addr;
1041 }
1042 
1043 
1044 const LocalArray&
array() const1045 LocalArrayValue::array() const
1046 {
1047    return m_array;
1048 }
1049 
1050 void
forward_del_use(Instr * instr)1051 LocalArrayValue::forward_del_use(Instr *instr)
1052 {
1053    if (m_addr && m_addr->as_register())
1054       m_addr->as_register()->del_use(instr);
1055 }
1056 
1057 void
forward_add_use(Instr * instr)1058 LocalArrayValue::forward_add_use(Instr *instr)
1059 {
1060    if (m_addr && m_addr->as_register())
1061       m_addr->as_register()->add_use(instr);
1062 }
1063 
1064 void
accept(RegisterVisitor & vistor)1065 LocalArrayValue::accept(RegisterVisitor& vistor)
1066 {
1067    vistor.visit(*this);
1068 }
1069 
1070 void
accept(ConstRegisterVisitor & vistor) const1071 LocalArrayValue::accept(ConstRegisterVisitor& vistor) const
1072 {
1073    vistor.visit(*this);
1074 }
1075 
1076 void
add_parent_to_array(Instr * instr)1077 LocalArrayValue::add_parent_to_array(Instr *instr)
1078 {
1079    if (m_addr)
1080       m_array.add_parent_to_elements(chan(), instr);
1081 }
1082 
1083 void
del_parent_from_array(Instr * instr)1084 LocalArrayValue::del_parent_from_array(Instr *instr)
1085 {
1086    m_array.del_parent(instr);
1087 }
1088 
1089 void
print(std::ostream & os) const1090 LocalArrayValue::print(std::ostream& os) const
1091 {
1092    int offset = sel() - m_array.sel();
1093    os << "A" << m_array.sel() << "[";
1094    if (offset > 0 && m_addr)
1095       os << offset << "+" << *m_addr;
1096    else if (m_addr)
1097       os << *m_addr;
1098    else
1099       os << offset;
1100    os << "]." << chanchar[chan()];
1101 }
1102 
1103 bool
ready(int block,int index) const1104 LocalArrayValue::ready(int block, int index) const
1105 {
1106    return m_addr ? (m_array.ready_for_indirect(block, index, chan()) &&
1107                     m_addr->ready(block, index))
1108                  : m_array.ready_for_direct(block, index, chan());
1109 }
1110 
ValueComparer()1111 ValueComparer::ValueComparer():
1112     m_result(false),
1113     m_register(nullptr),
1114     m_array(nullptr),
1115     m_array_value(nullptr),
1116     m_uniform_value(nullptr),
1117     m_literal_value(nullptr),
1118     m_inline_constant(nullptr)
1119 {
1120 }
1121 
ValueComparer(const Register * value)1122 ValueComparer::ValueComparer(const Register *value):
1123     m_result(false),
1124     m_register(value),
1125     m_array(nullptr),
1126     m_array_value(nullptr),
1127     m_uniform_value(nullptr),
1128     m_literal_value(nullptr),
1129     m_inline_constant(nullptr)
1130 {
1131 }
1132 
ValueComparer(const LocalArray * value)1133 ValueComparer::ValueComparer(const LocalArray *value):
1134     m_result(false),
1135     m_register(nullptr),
1136     m_array(value),
1137     m_array_value(nullptr),
1138     m_uniform_value(nullptr),
1139     m_literal_value(nullptr),
1140     m_inline_constant(nullptr)
1141 {
1142 }
1143 
ValueComparer(const LocalArrayValue * value)1144 ValueComparer::ValueComparer(const LocalArrayValue *value):
1145     m_result(false),
1146     m_register(nullptr),
1147     m_array(nullptr),
1148     m_array_value(value),
1149     m_uniform_value(nullptr),
1150     m_literal_value(nullptr),
1151     m_inline_constant(nullptr)
1152 {
1153 }
1154 
ValueComparer(const UniformValue * value)1155 ValueComparer::ValueComparer(const UniformValue *value):
1156     m_result(false),
1157     m_register(nullptr),
1158     m_array(nullptr),
1159     m_array_value(nullptr),
1160     m_uniform_value(value),
1161     m_literal_value(nullptr),
1162     m_inline_constant(nullptr)
1163 {
1164 }
1165 
ValueComparer(const LiteralConstant * value)1166 ValueComparer::ValueComparer(const LiteralConstant *value):
1167     m_result(false),
1168     m_register(nullptr),
1169     m_array(nullptr),
1170     m_array_value(nullptr),
1171     m_uniform_value(nullptr),
1172     m_literal_value(value),
1173     m_inline_constant(nullptr)
1174 {
1175 }
1176 
ValueComparer(const InlineConstant * value)1177 ValueComparer::ValueComparer(const InlineConstant *value):
1178     m_result(false),
1179     m_register(nullptr),
1180     m_array(nullptr),
1181     m_array_value(nullptr),
1182     m_uniform_value(nullptr),
1183     m_literal_value(nullptr),
1184     m_inline_constant(value)
1185 {
1186 }
1187 
1188 void
visit(const Register & other)1189 ValueComparer::visit(const Register& other)
1190 {
1191    (void)other;
1192    if (m_register) {
1193       m_result = other.flags() == m_register->flags();
1194    } else
1195       m_result = false;
1196 };
1197 
1198 void
visit(const LocalArray & other)1199 ValueComparer::visit(const LocalArray& other)
1200 {
1201    m_result = false;
1202    if (m_array) {
1203       m_result =
1204          m_array->size() == other.size() && m_array->nchannels() == other.nchannels();
1205    }
1206 };
1207 
1208 void
visit(const LocalArrayValue & other)1209 ValueComparer::visit(const LocalArrayValue& other)
1210 {
1211    m_result = false;
1212    if (m_array_value) {
1213       m_result = m_array_value->array().equal_to(other.array());
1214       if (m_result) {
1215          auto my_addr = m_array_value->addr();
1216          auto other_addr = other.addr();
1217          if (my_addr && other_addr) {
1218             m_result = my_addr->equal_to(*other_addr);
1219          } else {
1220             m_result = !my_addr && !other_addr;
1221          }
1222       }
1223    }
1224 };
1225 
1226 void
visit(const UniformValue & value)1227 ValueComparer::visit(const UniformValue& value)
1228 {
1229    m_result = false;
1230    if (m_uniform_value) {
1231       m_result = m_uniform_value->kcache_bank() == value.kcache_bank();
1232       if (m_result) {
1233          auto my_buf_addr = m_uniform_value->buf_addr();
1234          auto other_buf_addr = value.buf_addr();
1235          if (my_buf_addr && other_buf_addr) {
1236             m_result = my_buf_addr->equal_to(*other_buf_addr);
1237          } else {
1238             m_result = !my_buf_addr && !other_buf_addr;
1239          }
1240       }
1241    }
1242 };
1243 
1244 void
visit(const LiteralConstant & other)1245 ValueComparer::visit(const LiteralConstant& other)
1246 {
1247    m_result = m_literal_value && (m_literal_value->value() == other.value());
1248 };
1249 
1250 void
visit(const InlineConstant & other)1251 ValueComparer::visit(const InlineConstant& other)
1252 {
1253    (void)other;
1254    m_result = !!m_inline_constant;
1255 };
1256 
1257 class CheckConstValue : public ConstRegisterVisitor {
1258 public:
CheckConstValue(uint32_t _test_value)1259    CheckConstValue(uint32_t _test_value):
1260        test_value(_test_value)
1261    {
1262    }
CheckConstValue(float _test_value)1263    CheckConstValue(float _test_value):
1264        test_value(fui(_test_value))
1265    {
1266    }
1267 
visit(const Register & value)1268    void visit(const Register& value) override { (void)value; }
visit(const LocalArray & value)1269    void visit(const LocalArray& value) override { (void)value; }
visit(const LocalArrayValue & value)1270    void visit(const LocalArrayValue& value) override { (void)value; }
visit(const UniformValue & value)1271    void visit(const UniformValue& value) override { (void)value; }
1272 
visit(const LiteralConstant & value)1273    void visit(const LiteralConstant& value) override
1274    {
1275       result = value.value() == test_value;
1276    }
visit(const InlineConstant & value)1277    void visit(const InlineConstant& value) override
1278    {
1279       switch (test_value) {
1280       case 0:
1281          result = value.sel() == ALU_SRC_0;
1282          break;
1283       case 1:
1284          result = value.sel() == ALU_SRC_1_INT;
1285          break;
1286       case 0x3f800000 /* 1.0f */:
1287          result = value.sel() == ALU_SRC_1;
1288          break;
1289       case 0x3f000000 /* 0.5f */:
1290          result = value.sel() == ALU_SRC_0_5;
1291          break;
1292       }
1293    }
1294 
1295    uint32_t test_value;
1296    bool result{false};
1297 };
1298 
1299 bool
value_is_const_uint(const VirtualValue & val,uint32_t value)1300 value_is_const_uint(const VirtualValue& val, uint32_t value)
1301 {
1302    CheckConstValue test(value);
1303    val.accept(test);
1304    return test.result;
1305 }
1306 
1307 bool
value_is_const_float(const VirtualValue & val,float value)1308 value_is_const_float(const VirtualValue& val, float value)
1309 {
1310    CheckConstValue test(value);
1311    val.accept(test);
1312    return test.result;
1313 }
1314 
1315 } // namespace r600
1316