1/* -*- mesa-c++  -*-
2 *
3 * Copyright (c) 2018-2019 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_value_gpr.h"
28#include "sfn_valuepool.h"
29#include "sfn_debug.h"
30#include "sfn_liverange.h"
31
32namespace r600 {
33
34using std::vector;
35using std::array;
36
37GPRValue::GPRValue(uint32_t sel, uint32_t chan, int base_offset):
38   Value(Value::gpr, chan),
39   m_sel(sel),
40   m_base_offset(base_offset),
41   m_input(false),
42   m_pin_to_channel(false),
43   m_keep_alive(false)
44{
45}
46
47GPRValue::GPRValue(uint32_t sel, uint32_t chan):
48   Value(Value::gpr, chan),
49   m_sel(sel),
50   m_base_offset(0),
51   m_input(false),
52   m_pin_to_channel(false),
53   m_keep_alive(false)
54{
55}
56
57uint32_t GPRValue::sel() const
58{
59   return m_sel;
60}
61
62void GPRValue::do_print(std::ostream& os) const
63{
64   os << 'R';
65   os << m_sel;
66   os << '.' << component_names[chan()];
67}
68
69bool GPRValue::is_equal_to(const Value& other) const
70{
71   assert(other.type() == Value::Type::gpr);
72   const auto& rhs = static_cast<const GPRValue&>(other);
73   return (sel() == rhs.sel() &&
74           chan() == rhs.chan());
75}
76
77void GPRValue::do_print(std::ostream& os, UNUSED const PrintFlags& flags) const
78{
79   os << 'R';
80   os << m_sel;
81   os << '.' << component_names[chan()];
82}
83
84GPRVector::GPRVector(const GPRVector& orig):
85   Value(gpr_vector),
86   m_elms(orig.m_elms),
87   m_valid(orig.m_valid)
88{
89}
90
91GPRVector::GPRVector(std::array<PValue,4> elms):
92   Value(gpr_vector),
93   m_elms(elms),
94   m_valid(false)
95{
96   for (unsigned i = 0; i < 4; ++i)
97      if (!m_elms[i] || (m_elms[i]->type() != Value::gpr)) {
98         assert(0 && "GPR vector not valid because element missing or nit a GPR");
99         return;
100      }
101   unsigned sel = m_elms[0]->sel();
102   for (unsigned i = 1; i < 4; ++i)
103      if (m_elms[i]->sel() != sel) {
104         assert(0 && "GPR vector not valid because sel is not equal for all elements");
105         return;
106      }
107   m_valid = true;
108}
109
110GPRVector::GPRVector(uint32_t sel, std::array<uint32_t,4> swizzle):
111   Value (gpr_vector),
112   m_valid(true)
113{
114   for (int i = 0; i < 4; ++i)
115      m_elms[i] = PValue(new GPRValue(sel, swizzle[i]));
116}
117
118GPRVector::GPRVector(const GPRVector& orig, const std::array<uint8_t,4>& swizzle)
119{
120      for (int i = 0; i < 4; ++i)
121         m_elms[i] = orig.reg_i(swizzle[i]);
122      m_valid = orig.m_valid;
123}
124
125void GPRVector::validate() const
126{
127   assert(m_elms[0]);
128   uint32_t sel = m_elms[0]->sel();
129   if (sel >= 124)
130      return;
131
132   for (unsigned i = 1; i < 4; ++i) {
133      assert(m_elms[i]);
134      if (sel != m_elms[i]->sel())
135         return;
136   }
137
138   m_valid = true;
139}
140
141uint32_t GPRVector::sel() const
142{
143   validate();
144   assert(m_valid);
145   return m_elms[0] ? m_elms[0]->sel() : 999;
146}
147
148void GPRVector::set_reg_i(int i, PValue reg)
149{
150   m_elms[i] = reg;
151}
152
153void GPRVector::pin_to_channel(int i)
154{
155   auto& v = static_cast<GPRValue&>(*m_elms[i]);
156   v.set_pin_to_channel();
157}
158
159void GPRVector::pin_all_to_channel()
160{
161   for (auto& v: m_elms) {
162      auto& c = static_cast<GPRValue&>(*v);
163      c.set_pin_to_channel();
164   }
165}
166
167void GPRVector::do_print(std::ostream& os) const
168{
169   os << "R" << sel() << ".";
170   for (int i = 0; i < 4; ++i)
171      os << (m_elms[i] ? component_names[m_elms[i]->chan() < 8 ? m_elms[i]->chan() : 8] : '?');
172}
173
174void GPRVector::swizzle(const Swizzle& swz)
175{
176   Values v(m_elms);
177   for (uint32_t i = 0; i < 4; ++i)
178      if (i != swz[i]) {
179         assert(swz[i] < 4);
180         m_elms[i] = v[swz[i]];
181      }
182}
183
184bool GPRVector::is_equal_to(const Value& other) const
185{
186   if (other.type() != gpr_vector) {
187      std::cerr << "t";
188      return false;
189   }
190
191   const GPRVector& o = static_cast<const GPRVector&>(other);
192
193   for (int i = 0; i < 4; ++i) {
194      if (*m_elms[i] != *o.m_elms[i]) {
195         std::cerr << "elm" << i;
196         return false;
197      }
198   }
199   return true;
200}
201
202
203GPRArrayValue::GPRArrayValue(PValue value, PValue addr, GPRArray *array):
204   Value(gpr_array_value, value->chan()),
205   m_value(value),
206   m_addr(addr),
207   m_array(array)
208{
209}
210
211GPRArrayValue::GPRArrayValue(PValue value, GPRArray *array):
212   Value(gpr_array_value, value->chan()),
213   m_value(value),
214   m_array(array)
215{
216}
217
218static const char *swz_char = "xyzw01_";
219
220void GPRArrayValue::do_print(std::ostream& os) const
221{
222   assert(m_array);
223   os << "R"  << m_value->sel();
224   if (m_addr) {
225      os <<  "[" << *m_addr  << "] ";
226   }
227   os << swz_char[m_value->chan()];
228
229   os << "(" << *m_array << ")";
230}
231
232bool GPRArrayValue::is_equal_to(const Value& other) const
233{
234   const GPRArrayValue& v = static_cast<const GPRArrayValue&>(other);
235
236   return *m_value == *v.m_value &&
237         *m_array == *v.m_array;
238}
239
240void GPRArrayValue::record_read(LiverangeEvaluator& ev) const
241{
242   if (m_addr) {
243      ev.record_read(*m_addr);
244      unsigned chan = m_value->chan();
245      assert(m_array);
246      m_array->record_read(ev, chan);
247   } else
248      ev.record_read(*m_value);
249}
250
251void GPRArrayValue::record_write(LiverangeEvaluator& ev) const
252{
253   if (m_addr) {
254      ev.record_read(*m_addr);
255      unsigned chan = m_value->chan();
256      assert(m_array);
257      m_array->record_write(ev, chan);
258   } else
259      ev.record_write(*m_value);
260}
261
262void GPRArrayValue::reset_value(PValue new_value)
263{
264   m_value = new_value;
265}
266
267void GPRArrayValue::reset_addr(PValue new_addr)
268{
269   m_addr = new_addr;
270}
271
272
273GPRArray::GPRArray(int base, int size, int mask, int frac):
274   Value (gpr_vector),
275   m_base_index(base),
276   m_component_mask(mask),
277   m_frac(frac)
278{
279   m_values.resize(size);
280   for (int i = 0; i < size; ++i) {
281      for (int j = 0; j < 4; ++j) {
282         if (mask & (1 << j)) {
283            auto gpr = new GPRValue(base + i, j);
284            /* If we want to use sb, we have to keep arrays
285             * alife for the whole shader range, otherwise the sb scheduler
286             * thinks is not capable to rename non-array uses of these registers */
287            gpr->set_as_input();
288            gpr->set_keep_alive();
289            m_values[i].set_reg_i(j, PValue(gpr));
290
291         }
292      }
293   }
294}
295
296uint32_t GPRArray::sel() const
297{
298   return m_base_index;
299}
300
301static const char *compchar = "xyzw";
302void GPRArray::do_print(std::ostream& os) const
303{
304   os << "ARRAY[R" << sel() << "..R" << sel() + m_values.size()  - 1 << "].";
305   for (int j = 0; j < 4; ++j) {
306      if (m_component_mask & (1 << j))
307         os << compchar[j];
308   }
309}
310
311bool GPRArray::is_equal_to(const Value& other) const
312{
313   const GPRArray& o = static_cast<const GPRArray&>(other);
314   return o.sel() == sel() &&
315         o.m_values.size() == m_values.size() &&
316         o.m_component_mask == m_component_mask;
317}
318
319uint32_t GPRArrayValue::sel() const
320{
321   return m_value->sel();
322}
323
324PValue GPRArray::get_indirect(unsigned index, PValue indirect, unsigned component)
325{
326   assert(index < m_values.size());
327   assert(m_component_mask & (1 << (component + m_frac)));
328
329   sfn_log << SfnLog::reg << "Create indirect register from " << *this;
330
331   PValue v = m_values[index].reg_i(component + m_frac);
332   assert(v);
333
334   sfn_log << SfnLog::reg << " ->  " << *v;
335
336   if (indirect) {
337      sfn_log << SfnLog::reg << "["  << *indirect << "]";
338      switch (indirect->type()) {
339      case Value::literal: {
340         const LiteralValue& lv = static_cast<const LiteralValue&>(*indirect);
341         v = m_values[lv.value()].reg_i(component + m_frac);
342         break;
343      }
344      case Value::gpr:  {
345         v = PValue(new GPRArrayValue(v, indirect, this));
346         sfn_log << SfnLog::reg << "(" << *v << ")";
347         break;
348      }
349      default:
350         assert(0 && !"Indirect addressing must be literal value or GPR");
351      }
352   }
353   sfn_log << SfnLog::reg <<"  -> " << *v << "\n";
354   return v;
355}
356
357void GPRArray::record_read(LiverangeEvaluator& ev, int chan) const
358{
359   for (auto& v: m_values)
360      ev.record_read(*v.reg_i(chan), true);
361}
362
363void GPRArray::record_write(LiverangeEvaluator& ev, int chan) const
364{
365   for (auto& v: m_values)
366      ev.record_write(*v.reg_i(chan), true);
367}
368
369void GPRArray::collect_registers(ValueMap& output) const
370{
371   for (auto& v: m_values) {
372      for (int i = 0; i < 4; ++i) {
373         auto vv = v.reg_i(i);
374         if (vv)
375            output.insert(vv);
376      }
377   }
378}
379
380}
381