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