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_debug.h"
28 #include "sfn_value_gpr.h"
29 #include "sfn_valuepool.h"
30 
31 #include <iostream>
32 #include <queue>
33 
34 namespace r600 {
35 
36 using std::vector;
37 using std::pair;
38 using std::make_pair;
39 using std::queue;
40 
ValuePool()41 ValuePool::ValuePool():
42    m_next_register_index(0),
43    current_temp_reg_index(0),
44    next_temp_reg_comp(4)
45 {
46 }
47 
48 PValue ValuePool::m_undef = Value::zero;
49 
vec_from_nir(const nir_dest & dst,int num_components)50 GPRVector ValuePool::vec_from_nir(const nir_dest& dst, int num_components)
51 {
52    std::array<PValue, 4> result;
53    for (int i = 0; i < 4; ++i)
54       result[i] = from_nir(dst, i < num_components ? i : 7);
55    return GPRVector(result);
56 }
57 
varvec_from_nir(const nir_dest & dst,int num_components)58 std::vector<PValue> ValuePool::varvec_from_nir(const nir_dest& dst, int num_components)
59 {
60    std::vector<PValue> result(num_components);
61    for (int i = 0; i < num_components; ++i)
62       result[i] = from_nir(dst, i);
63    return result;
64 }
65 
66 
varvec_from_nir(const nir_src & src,int num_components)67 std::vector<PValue> ValuePool::varvec_from_nir(const nir_src& src, int num_components)
68 {
69    std::vector<PValue> result(num_components);
70    int i;
71    for (i = 0; i < num_components; ++i)
72       result[i] = from_nir(src, i);
73 
74    return result;
75 }
76 
77 
from_nir(const nir_src & v,unsigned component,unsigned swizzled)78 PValue ValuePool::from_nir(const nir_src& v, unsigned component, unsigned swizzled)
79 {
80    sfn_log << SfnLog::reg << "Search " << (v.is_ssa ? "ssa_reg " : "reg ")
81            << (v.is_ssa ? v.ssa->index : v.reg.reg->index);
82 
83    if (!v.is_ssa) {
84       int idx = lookup_register_index(v);
85       sfn_log << SfnLog::reg << "  -> got index " <<  idx << "\n";
86       if (idx >= 0) {
87          auto reg = lookup_register(idx, swizzled, false);
88          if (reg) {
89             if (reg->type() == Value::gpr_vector) {
90                auto& array = static_cast<GPRArray&>(*reg);
91                reg = array.get_indirect(v.reg.base_offset,
92                                         v.reg.indirect ?
93                                            from_nir(*v.reg.indirect, 0, 0) : nullptr,
94                                         component);
95             }
96             return reg;
97          }
98       }
99       assert(0 && "local registers should always be found");
100    }
101 
102    unsigned index = v.ssa->index;
103    /* For undefs we use zero and let ()yet to be implemeneted dce deal with it */
104    if (m_ssa_undef.find(index) != m_ssa_undef.end())
105       return Value::zero;
106 
107 
108    int idx = lookup_register_index(v);
109    sfn_log << SfnLog::reg << "  -> got index " <<  idx << "\n";
110    if (idx >= 0) {
111       auto reg = lookup_register(idx, swizzled, false);
112       if (reg)
113          return reg;
114    }
115 
116    auto literal_val = nir_src_as_const_value(v);
117    if (literal_val) {
118       assert(v.is_ssa);
119       switch (v.ssa->bit_size) {
120       case 1:
121          return PValue(new LiteralValue(literal_val[swizzled].b ? 0xffffffff : 0, component));
122       case 32:
123          return literal(literal_val[swizzled].u32);
124       default:
125          sfn_log << SfnLog::reg << "Unsupported bit size " << v.ssa->bit_size
126                  << " fall back to 32\n";
127          return PValue(new LiteralValue(literal_val[swizzled].u32, component));
128       }
129    }
130 
131    return PValue();
132 }
133 
from_nir(const nir_src & v,unsigned component)134 PValue ValuePool::from_nir(const nir_src& v, unsigned component)
135 {
136    return from_nir(v, component, component);
137 }
138 
from_nir(const nir_tex_src & v,unsigned component)139 PValue ValuePool::from_nir(const nir_tex_src &v, unsigned component)
140 {
141    return from_nir(v.src, component, component);
142 }
143 
from_nir(const nir_alu_src & v,unsigned component)144 PValue ValuePool::from_nir(const nir_alu_src &v, unsigned component)
145 {
146    return from_nir(v.src, component, v.swizzle[component]);
147 }
148 
get_temp_register(int channel)149 PGPRValue ValuePool::get_temp_register(int channel)
150 {
151    /* Skip to next register to get the channel we want */
152    if (channel >= 0) {
153       if (next_temp_reg_comp <= channel)
154          next_temp_reg_comp = channel;
155       else
156          next_temp_reg_comp = 4;
157    }
158 
159    if (next_temp_reg_comp > 3) {
160       current_temp_reg_index = allocate_temp_register();
161       next_temp_reg_comp = 0;
162    }
163    return std::make_shared<GPRValue>(current_temp_reg_index, next_temp_reg_comp++);
164 }
165 
get_temp_vec4(const GPRVector::Swizzle & swizzle)166 GPRVector ValuePool::get_temp_vec4(const GPRVector::Swizzle& swizzle)
167 {
168    int sel = allocate_temp_register();
169    return GPRVector(sel, swizzle);
170 }
171 
create_register_from_nir_src(const nir_src & src,int comp)172 PValue ValuePool::create_register_from_nir_src(const nir_src& src, int comp)
173 {
174    int idx = src.is_ssa ? get_dst_ssa_register_index(*src.ssa):
175                           get_local_register_index(*src.reg.reg);
176 
177    auto retval = lookup_register(idx, comp, false);
178    if (!retval || retval->type() != Value::gpr || retval->type() != Value::gpr_array_value)
179       retval = create_register(idx, comp);
180    return retval;
181 }
182 
from_nir(const nir_alu_dest & v,unsigned component)183 PValue ValuePool::from_nir(const nir_alu_dest &v, unsigned component)
184 {
185    //assert(v->write_mask & (1 << component));
186    return from_nir(v.dest, component);
187 }
188 
lookup_register_index(const nir_dest & dst)189 int ValuePool::lookup_register_index(const nir_dest& dst)
190 {
191    return dst.is_ssa ? get_dst_ssa_register_index(dst.ssa):
192                        get_local_register_index(*dst.reg.reg);
193 }
194 
lookup_register_index(const nir_src & src) const195 int ValuePool::lookup_register_index(const nir_src& src) const
196 {
197    int index = 0;
198 
199    index = src.is_ssa ?
200               get_ssa_register_index(*src.ssa) :
201               get_local_register_index(*src.reg.reg);
202 
203    sfn_log << SfnLog::reg << " LIDX:" << index;
204 
205    auto r = m_register_map.find(index);
206    if (r == m_register_map.end()) {
207       return -1;
208    }
209    return static_cast<int>(r->second.index);
210 }
211 
212 
allocate_temp_register()213 int ValuePool::allocate_temp_register()
214 {
215    return m_next_register_index++;
216 }
217 
218 
from_nir(const nir_dest & v,unsigned component)219 PValue ValuePool::from_nir(const nir_dest& v, unsigned component)
220 {
221    int idx = lookup_register_index(v);
222    sfn_log << SfnLog::reg << __func__  << ": ";
223    if (v.is_ssa)
224       sfn_log << "ssa_" << v.ssa.index;
225    else
226       sfn_log << "r" << v.reg.reg->index;
227    sfn_log << " -> " << idx << "\n";
228 
229    auto retval = lookup_register(idx, component, false);
230    if (!retval)
231       retval = create_register(idx, component);
232 
233    if (retval->type() == Value::gpr_vector) {
234       assert(!v.is_ssa);
235       auto& array = static_cast<GPRArray&>(*retval);
236       retval = array.get_indirect(v.reg.base_offset,
237                                   v.reg.indirect ?
238                                   from_nir(*v.reg.indirect, 0, 0) : nullptr,
239                                   component);
240    }
241 
242    return retval;
243 }
244 
get_temp_registers() const245 ValueMap ValuePool::get_temp_registers() const
246 {
247    ValueMap result;
248 
249    for (auto& v : m_registers) {
250       if (v.second->type() == Value::gpr)
251          result.insert(v.second);
252       else if (v.second->type() == Value::gpr_vector) {
253          auto& array = static_cast<GPRArray&>(*v.second);
254          array.collect_registers(result);
255       }
256    }
257    return result;
258 }
259 
260 static const char swz[] = "xyzw01?_";
261 
create_register(unsigned sel,unsigned swizzle)262 PValue ValuePool::create_register(unsigned sel, unsigned swizzle)
263 {
264    sfn_log << SfnLog::reg
265            <<"Create register " << sel  << '.' << swz[swizzle] << "\n";
266    auto retval = PValue(new GPRValue(sel, swizzle));
267    m_registers[(sel << 3) + swizzle] = retval;
268    return retval;
269 }
270 
inject_register(unsigned sel,unsigned swizzle,const PValue & reg,bool map)271 bool ValuePool::inject_register(unsigned sel, unsigned swizzle,
272                                 const PValue& reg, bool map)
273 {
274    uint32_t ssa_index = sel;
275 
276    if (map) {
277       auto pos = m_ssa_register_map.find(sel);
278       if (pos == m_ssa_register_map.end())
279          ssa_index = m_next_register_index++;
280       else
281          ssa_index = pos->second;
282    }
283 
284    sfn_log << SfnLog::reg
285            << "Inject register " << sel  << '.' << swz[swizzle]
286            << " at index " <<  ssa_index << " ...";
287 
288    if (map)
289       m_ssa_register_map[sel] = ssa_index;
290 
291    allocate_with_mask(ssa_index, swizzle, true);
292 
293    unsigned idx = (ssa_index << 3) + swizzle;
294    auto p = m_registers.find(idx);
295    if ( (p != m_registers.end()) && *p->second != *reg) {
296       std::cerr << "Register location (" << ssa_index << ", " << swizzle << ") was already reserved\n";
297       assert(0);
298       return false;
299    }
300    sfn_log << SfnLog::reg << " at idx:" << idx << " to " << *reg << "\n";
301    m_registers[idx] = reg;
302 
303    if (m_next_register_index <= ssa_index)
304       m_next_register_index = ssa_index + 1;
305    return true;
306 }
307 
308 
lookup_register(unsigned sel,unsigned swizzle,bool required)309 PValue ValuePool::lookup_register(unsigned sel, unsigned swizzle,
310                                   bool required)
311 {
312 
313    PValue retval;
314    sfn_log << SfnLog::reg
315            << "lookup register " << sel  << '.' << swz[swizzle] << "("
316            << ((sel << 3) + swizzle) << ")...";
317 
318 
319    auto reg = m_registers.find((sel << 3) + swizzle);
320    if (reg != m_registers.end()) {
321       sfn_log << SfnLog::reg << " -> Found " << *reg->second << "\n";
322       retval = reg->second;
323    } else if (swizzle == 7) {
324       PValue retval = create_register(sel, swizzle);
325       sfn_log << SfnLog::reg << " -> Created " << *retval << "\n";
326    } else if (required) {
327       sfn_log << SfnLog::reg << "Register (" << sel << ", "
328               << swizzle << ") not found but required\n";
329       assert(0 && "Unallocated register value requested\n");
330    }
331    sfn_log << SfnLog::reg << " -> Not required and not  allocated\n";
332    return retval;
333 }
334 
get_dst_ssa_register_index(const nir_ssa_def & ssa)335 unsigned ValuePool::get_dst_ssa_register_index(const nir_ssa_def& ssa)
336 {
337    sfn_log << SfnLog::reg << __func__ << ": search dst ssa "
338            << ssa.index;
339 
340    auto pos = m_ssa_register_map.find(ssa.index);
341    if (pos == m_ssa_register_map.end()) {
342       sfn_log << SfnLog::reg << " Need to allocate ...";
343       allocate_ssa_register(ssa);
344       pos = m_ssa_register_map.find(ssa.index);
345       assert(pos != m_ssa_register_map.end());
346    }
347    sfn_log << SfnLog::reg << "... got " << pos->second << "\n";
348    return pos->second;
349 }
350 
get_ssa_register_index(const nir_ssa_def & ssa) const351 unsigned ValuePool::get_ssa_register_index(const nir_ssa_def& ssa) const
352 {
353    sfn_log << SfnLog::reg << __func__ << ": search ssa "
354            << ssa.index;
355 
356    auto pos = m_ssa_register_map.find(ssa.index);
357    sfn_log << SfnLog::reg << " got " << pos->second<< "\n";
358    if (pos == m_ssa_register_map.end()) {
359       sfn_log << SfnLog::reg << __func__ << ": ssa register "
360               << ssa.index << " lookup failed\n";
361       return -1;
362    }
363    return pos->second;
364 }
365 
get_local_register_index(const nir_register & reg)366 unsigned ValuePool::get_local_register_index(const nir_register& reg)
367 {
368    unsigned index = reg.index | 0x80000000;
369 
370    auto pos = m_ssa_register_map.find(index);
371    if (pos == m_ssa_register_map.end()) {
372       allocate_local_register(reg);
373       pos = m_ssa_register_map.find(index);
374       assert(pos != m_ssa_register_map.end());
375    }
376    return pos->second;
377 }
378 
get_local_register_index(const nir_register & reg) const379 unsigned ValuePool::get_local_register_index(const nir_register& reg) const
380 {
381    unsigned index = reg.index | 0x80000000;
382    auto pos = m_ssa_register_map.find(index);
383    if (pos == m_ssa_register_map.end()) {
384       sfn_log << SfnLog::err << __func__ << ": local register "
385               << reg.index << " lookup failed";
386       return -1;
387    }
388    return pos->second;
389 }
390 
allocate_ssa_register(const nir_ssa_def & ssa)391 void ValuePool::allocate_ssa_register(const nir_ssa_def& ssa)
392 {
393    sfn_log << SfnLog::reg << "ValuePool: Allocate ssa register " << ssa.index
394            << " as " << m_next_register_index << "\n";
395    int index = m_next_register_index++;
396    m_ssa_register_map[ssa.index] = index;
397    allocate_with_mask(index, 0xf, true);
398 }
399 
allocate_arrays(array_list & arrays)400 void ValuePool::allocate_arrays(array_list& arrays)
401 {
402    int ncomponents = 0;
403    int current_index = m_next_register_index;
404    unsigned instance = 0;
405 
406    while (!arrays.empty()) {
407       auto a = arrays.top();
408       arrays.pop();
409 
410       /* This is a bit hackish, return an id that encodes the array merge. To make sure
411        * that the mapping doesn't go wrong we have to make sure the arrays is longer than
412        * the number of instances in this arrays slot */
413       if (a.ncomponents + ncomponents > 4 ||
414           a.length < instance) {
415          current_index = m_next_register_index;
416          ncomponents = 0;
417          instance = 0;
418       }
419 
420       if (ncomponents == 0)
421          m_next_register_index += a.length;
422 
423       uint32_t mask = ((1 << a.ncomponents) - 1) << ncomponents;
424 
425       PGPRArray array = PGPRArray(new GPRArray(current_index, a.length, mask, ncomponents));
426 
427       m_reg_arrays.push_back(array);
428 
429       sfn_log << SfnLog::reg << "Add array at "<< current_index
430               << " of size " << a.length << " with " << a.ncomponents
431               << " components, mask " << mask << "\n";
432 
433       m_ssa_register_map[a.index | 0x80000000] = current_index + instance;
434 
435       for (unsigned  i = 0; i < a.ncomponents; ++i)
436          m_registers[((current_index  + instance) << 3) + i] = array;
437 
438       VRec next_reg = {current_index + instance, mask, mask};
439       m_register_map[current_index + instance] = next_reg;
440 
441       ncomponents += a.ncomponents;
442       ++instance;
443    }
444 }
445 
allocate_local_register(const nir_register & reg)446 void ValuePool::allocate_local_register(const nir_register& reg)
447 {
448    int index = m_next_register_index++;
449    m_ssa_register_map[reg.index | 0x80000000] = index;
450    allocate_with_mask(index, 0xf, true);
451 
452    /* Create actual register and map it */;
453    for (int i = 0; i < 4; ++i) {
454       int k = (index << 3) + i;
455       m_registers[k] = std::make_shared<GPRValue>(index, i);
456    }
457 }
458 
allocate_local_register(const nir_register & reg,array_list & arrays)459 void ValuePool::allocate_local_register(const nir_register& reg, array_list& arrays)
460 {
461    sfn_log << SfnLog::reg << "ValuePool: Allocate local register " << reg.index
462            << " as " << m_next_register_index << "\n";
463 
464    if (reg.num_array_elems) {
465       array_entry ae = {reg.index, reg.num_array_elems, reg.num_components};
466       arrays.push(ae);
467    }
468    else
469       allocate_local_register(reg);
470 }
471 
create_undef(nir_ssa_undef_instr * instr)472 bool ValuePool::create_undef(nir_ssa_undef_instr* instr)
473 {
474    m_ssa_undef.insert(instr->def.index);
475    return true;
476 }
477 
allocate_with_mask(unsigned index,unsigned mask,bool pre_alloc)478 int ValuePool::allocate_with_mask(unsigned index, unsigned mask, bool pre_alloc)
479 {
480    int retval;
481    VRec next_register = { index, mask };
482 
483    sfn_log << SfnLog::reg << (pre_alloc ? "Pre-alloc" : "Allocate")
484            << " register (" << index << ", " << mask << ")\n";
485    retval = index;
486    auto r = m_register_map.find(index);
487 
488    if (r != m_register_map.end()) {
489       if ((r->second.mask & next_register.mask) &&
490           !(r->second.pre_alloc_mask & next_register.mask)) {
491          std::cerr << "r600 ERR: register ("
492                    << index << ", " << mask
493                    << ") already allocated as (" << r->second.index << ", "
494                    << r->second.mask << ", " << r->second.pre_alloc_mask
495                    << ") \n";
496          retval = -1;
497       } else {
498          r->second.mask |= next_register.mask;
499          if (pre_alloc)
500             r->second.pre_alloc_mask |= next_register.mask;
501          retval = r->second.index;
502       }
503    } else  {
504       if (pre_alloc)
505          next_register.pre_alloc_mask = mask;
506       m_register_map[index] = next_register;
507       retval = next_register.index;
508    }
509 
510    sfn_log << SfnLog::reg << "Allocate register (" << index << "," << mask << ") in R"
511            << retval << "\n";
512 
513    return retval;
514 }
515 
literal(uint32_t value)516 PValue ValuePool::literal(uint32_t value)
517 {
518    auto l = m_literals.find(value);
519    if (l != m_literals.end())
520       return l->second;
521 
522    m_literals[value] = PValue(new LiteralValue(value));
523    return m_literals[value];
524 }
525 
526 }
527