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