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