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