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 41namespace r600 { 42 43std::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 61VirtualValue::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 69bool VirtualValue::ready(int block, int index) const 70{ 71 (void)block; 72 (void)index; 73 return true; 74} 75 76bool VirtualValue::is_virtual() const 77{ 78 return m_sel >= virtual_register_base; 79} 80 81class ValueComparer: public ConstRegisterVisitor { 82public: 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; 99private: 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 108class ValueCompareCreater: public ConstRegisterVisitor { 109public: 110 void visit(const Register& value) { compare = ValueComparer(&value);} 111 void visit(const LocalArray& value) {compare = ValueComparer(&value);} 112 void visit(const LocalArrayValue& value) {compare = ValueComparer(&value);} 113 void visit(const UniformValue& value) {compare = ValueComparer(&value);} 114 void visit(const LiteralConstant& value) {compare = ValueComparer(&value);} 115 void visit(const InlineConstant& value) {compare = ValueComparer(&value);} 116 117 ValueComparer compare; 118}; 119 120VirtualValue::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 136bool 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 152VirtualValue::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 173Register::Register(int sel, int chan, Pin pin): 174 VirtualValue(sel, chan, pin) 175{ 176} 177 178void Register::add_parent(Instr *instr) 179{ 180 m_parents.insert(instr); 181 instr->add_use(); 182 add_parent_to_array(instr); 183} 184 185void Register::add_parent_to_array(Instr *instr) 186{ 187 (void)instr; 188} 189 190void Register::del_parent(Instr *instr) 191{ 192 m_parents.erase(instr); 193 instr->dec_use(); 194 del_parent_from_array(instr); 195} 196 197void Register::del_parent_from_array(Instr *instr) 198{ 199 (void)instr; 200} 201 202 203void 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 213void 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 224bool 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 236void Register::accept(RegisterVisitor& visitor) 237{ 238 visitor.visit(*this); 239} 240 241void Register::accept(ConstRegisterVisitor& visitor) const 242{ 243 visitor.visit(*this); 244} 245 246 247void Register::pin_live_range(bool start, bool end) 248{ 249 m_pin_start = start; 250 m_pin_end = end; 251} 252 253void Register::set_is_ssa(bool value) 254{ 255 m_is_ssa = value; 256} 257 258void 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 266Register::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 332RegisterVec4::RegisterVec4(): 333 m_sel(-1), 334 m_swz({7,7,7,7}), 335 m_values({nullptr, nullptr, nullptr, nullptr}) 336{ 337} 338 339RegisterVec4::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 349RegisterVec4::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 357RegisterVec4::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 406void 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 414void RegisterVec4::del_use(Instr *instr) 415{ 416 for (auto& r: m_values) { 417 r->value()->del_use(instr); 418 } 419} 420 421bool 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 431int 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 439bool 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 450void 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 457bool 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 469RegisterVec4::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 475RegisterVec4::Element::Element(const RegisterVec4& parent, PRegister value): 476 m_parent(parent), 477 m_value(value) 478{ 479} 480 481LiteralConstant::LiteralConstant(uint32_t value): 482 VirtualValue(ALU_SRC_LITERAL, -1, pin_none), 483 m_value(value) 484{ 485} 486 487void LiteralConstant::accept(RegisterVisitor& vistor) 488{ 489 vistor.visit(*this); 490} 491 492void LiteralConstant::accept(ConstRegisterVisitor& vistor) const 493{ 494 vistor.visit(*this); 495} 496 497void LiteralConstant::print(std::ostream& os) const 498{ 499 os << "L[0x" << std::hex << m_value << std::dec << "]"; 500} 501 502LiteralConstant::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 529InlineConstant::InlineConstant(int sel, int chan): 530 VirtualValue(sel, chan, pin_none) 531{ 532} 533 534void InlineConstant::accept(RegisterVisitor& vistor) 535{ 536 vistor.visit(*this); 537} 538 539void InlineConstant::accept(ConstRegisterVisitor& vistor) const 540{ 541 vistor.visit(*this); 542} 543 544void 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 561std::map<std::string, std::pair<AluInlineConstants, bool>> InlineConstant::s_opmap; 562 563InlineConstant::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 618InlineConstant::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 644UniformValue::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 651UniformValue::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 658void UniformValue::accept(RegisterVisitor& vistor) 659{ 660 vistor.visit(*this); 661} 662 663void UniformValue::accept(ConstRegisterVisitor& vistor) const 664{ 665 vistor.visit(*this); 666} 667 668PVirtualValue UniformValue::buf_addr() const 669{ 670 return m_buf_addr; 671} 672 673void 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 683bool 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 697UniformValue::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 729LocalArray::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 757void LocalArray::accept(RegisterVisitor& vistor) 758{ 759 vistor.visit(*this); 760} 761 762void LocalArray::accept(ConstRegisterVisitor& vistor) const 763{ 764 vistor.visit(*this); 765} 766 767void 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 776size_t LocalArray::size() const 777{ 778 return m_size; 779} 780 781uint32_t LocalArray::nchannels() const 782{ 783 return m_nchannels; 784} 785 786PRegister 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 832bool 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 848bool 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 860LocalArrayValue::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 868const Register& LocalArray::operator ()(size_t idx, size_t chan) const 869{ 870 return *m_values[m_size * (chan - m_frac) + idx]; 871} 872 873LocalArrayValue::LocalArrayValue(PRegister reg, LocalArray& array): 874 LocalArrayValue(reg, nullptr, array) 875{ 876 877} 878 879 880PVirtualValue LocalArrayValue::addr() const 881{ 882 return m_addr; 883} 884 885const LocalArray& LocalArrayValue::array() const 886{ 887 return m_array; 888} 889 890 891void 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 897void 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 903void LocalArrayValue::accept(RegisterVisitor& vistor) 904{ 905 vistor.visit(*this); 906} 907 908void LocalArrayValue::accept(ConstRegisterVisitor& vistor) const 909{ 910 vistor.visit(*this); 911} 912 913void LocalArrayValue::add_parent_to_array(Instr *instr) 914{ 915 m_array.add_parent(instr); 916} 917 918void LocalArrayValue::del_parent_from_array(Instr *instr) 919{ 920 m_array.del_parent(instr); 921} 922 923void 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 936bool 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 943ValueComparer::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 953ValueComparer::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 963ValueComparer::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 973ValueComparer::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 983ValueComparer::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 993ValueComparer::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 1003ValueComparer::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 1013void ValueComparer::visit(const Register& other) 1014{ 1015 (void)other; 1016 m_result = !!m_register; 1017}; 1018 1019void 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 1028void 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 1045void 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 1062void ValueComparer::visit(const LiteralConstant& other) 1063{ 1064 m_result = m_literal_value && (m_literal_value->value() == other.value()); 1065}; 1066 1067void ValueComparer::visit(const InlineConstant& other) 1068{ 1069 (void)other; 1070 m_result = !!m_inline_constant; 1071}; 1072 1073 1074} // namespace r600 1075