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