Home | History | Annotate | Line # | Download | only in sfn
      1 /* -*- mesa-c++  -*-
      2  *
      3  * Copyright (c) 2018-2019 Collabora LTD
      4  *
      5  * Author: Gert Wollny <gert.wollny (at) 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 
     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 
     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 
     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 
     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 
     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 
    134 PValue ValuePool::from_nir(const nir_src& v, unsigned component)
    135 {
    136    return from_nir(v, component, component);
    137 }
    138 
    139 PValue ValuePool::from_nir(const nir_tex_src &v, unsigned component)
    140 {
    141    return from_nir(v.src, component, component);
    142 }
    143 
    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 
    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 
    166 GPRVector ValuePool::get_temp_vec4(const GPRVector::Swizzle& swizzle)
    167 {
    168    int sel = allocate_temp_register();
    169    return GPRVector(sel, swizzle);
    170 }
    171 
    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 
    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 
    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 
    195 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 
    213 int ValuePool::allocate_temp_register()
    214 {
    215    return m_next_register_index++;
    216 }
    217 
    218 
    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 
    245 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 
    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 
    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 
    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 
    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 
    351 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 
    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 
    379 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 
    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 
    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 
    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 
    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 
    472 bool ValuePool::create_undef(nir_ssa_undef_instr* instr)
    473 {
    474    m_ssa_undef.insert(instr->def.index);
    475    return true;
    476 }
    477 
    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 
    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