Home | History | Annotate | Line # | Download | only in sfn
      1 /* -*- mesa-c++  -*-
      2  *
      3  * Copyright (c) 2018 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 
     28 #ifndef SFN_VALUEPOOL_H
     29 #define SFN_VALUEPOOL_H
     30 
     31 #include "sfn_value.h"
     32 #include "sfn_value_gpr.h"
     33 
     34 #include <set>
     35 #include <queue>
     36 
     37 namespace r600 {
     38 
     39 using LiteralBuffer = std::map<unsigned, const nir_load_const_instr *>;
     40 
     41 class ValueMap {
     42 public:
     43    void insert(const PValue& v) {
     44       auto idx = index_from(v->sel(), v->chan());
     45       m_map[idx] = v;
     46    }
     47    PValue get_or_inject(uint32_t index, uint32_t chan) {
     48       auto idx = index_from(index, chan);
     49       auto v = m_map.find(idx);
     50       if (v == m_map.end()) {
     51          insert(PValue(new GPRValue(index, chan)));
     52          v = m_map.find(idx);
     53       }
     54       return v->second;
     55    }
     56    std::map<uint32_t, PValue>::const_iterator begin() const {return m_map.begin();}
     57    std::map<uint32_t, PValue>::const_iterator end() const {return m_map.end();}
     58 
     59 private:
     60    uint32_t index_from(uint32_t index, uint32_t chan) {
     61       return (index << 3) + chan;
     62    }
     63    std::map<uint32_t, PValue> m_map;
     64 };
     65 
     66 /** \brief Class to keep track of registers, uniforms, and literals
     67  * This class holds the references to the uniforms and the literals
     68  * and is responsible for allocating the registers.
     69  */
     70 class ValuePool
     71 {
     72 public:
     73 
     74    struct  array_entry {
     75       unsigned index;
     76       unsigned length;
     77       unsigned ncomponents;
     78 
     79       bool operator ()(const array_entry& a, const array_entry& b) const {
     80          return a.length < b.length || (a.length == b.length && a.ncomponents > b.ncomponents);
     81       }
     82    };
     83 
     84    using array_list = std::priority_queue<array_entry, std::vector<array_entry>,
     85                                           array_entry>;
     86 
     87    ValuePool();
     88 
     89 
     90    GPRVector vec_from_nir(const nir_dest& dst, int num_components);
     91 
     92    std::vector<PValue> varvec_from_nir(const nir_dest& src, int num_components);
     93    std::vector<PValue> varvec_from_nir(const nir_src& src, int num_components);
     94 
     95    PValue from_nir(const nir_src& v, unsigned component, unsigned swizzled);
     96 
     97    PValue from_nir(const nir_src& v, unsigned component);
     98    /** Get a register that is used as source register in an ALU instruction
     99     * The PValue holds one componet as specified. If the register refers to
    100     * a GPR it must already have been allocated, uniforms and literals on
    101     * the other hand might be pre-loaded.
    102     */
    103    PValue from_nir(const nir_alu_src& v, unsigned component);
    104 
    105    /** Get a register that is used as source register in an Texture instruction
    106     * The PValue holds one componet as specified.
    107     */
    108    PValue from_nir(const nir_tex_src& v, unsigned component);
    109 
    110    /** Allocate a register that is used as destination register in an ALU
    111     * instruction. The PValue holds one componet as specified.
    112     */
    113    PValue from_nir(const nir_alu_dest& v, unsigned component);
    114 
    115    /** Allocate a register that is used as destination register in any
    116     * instruction. The PValue holds one componet as specified.
    117     */
    118    PValue from_nir(const nir_dest& v, unsigned component);
    119 
    120 
    121    /** Inject a register into a given ssa index position
    122     * This is used to redirect loads from system values and vertex attributes
    123     * that are already loaded into registers */
    124    bool inject_register(unsigned sel, unsigned swizzle, const PValue &reg, bool map);
    125 
    126    /** Reserve space for a local register */
    127    void allocate_local_register(const nir_register& reg);
    128    void allocate_local_register(const nir_register &reg, array_list& arrays);
    129 
    130    void allocate_arrays(array_list& arrays);
    131 
    132 
    133    void increment_reserved_registers() {
    134       ++m_next_register_index;
    135    }
    136 
    137    void set_reserved_registers(unsigned rr) {
    138       m_next_register_index =rr;
    139    }
    140 
    141    /** Reserve a undef register, currently it uses (0,7),
    142     * \todo should be eliminated in the final pass
    143     */
    144    bool create_undef(nir_ssa_undef_instr* instr);
    145 
    146    /** Create a new register with the given index and store it in the
    147     * lookup map
    148     */
    149    PValue create_register_from_nir_src(const nir_src& sel, int comp);
    150 
    151    ValueMap get_temp_registers() const;
    152 
    153    PValue lookup_register(unsigned sel, unsigned swizzle, bool required);
    154 
    155    size_t register_count() const {return m_next_register_index;}
    156 
    157    PValue literal(uint32_t value);
    158 
    159    PGPRValue get_temp_register(int channel = -1);
    160 
    161    GPRVector get_temp_vec4(const GPRVector::Swizzle &swizzle = {0,1,2,3});
    162 
    163 protected:
    164    std::vector<PGPRArray> m_reg_arrays;
    165 
    166 private:
    167 
    168    /** Get the register index mapped from the NIR code to the r600 ir
    169     * \param index NIR index of register
    170     * \returns r600 ir inxex
    171     */
    172    int lookup_register_index(const nir_src& src) const;
    173 
    174    /** Get the register index mapped from the NIR code to the r600 ir
    175     * \param index NIR index of register
    176     * \returns r600 ir inxex
    177     */
    178    int lookup_register_index(const nir_dest& dst);
    179 
    180    /** Allocate a register that is is needed for lowering an instruction
    181     * that requires complex calculations,
    182     */
    183    int allocate_temp_register();
    184 
    185 
    186    PValue create_register(unsigned index, unsigned swizzle);
    187 
    188    unsigned get_dst_ssa_register_index(const nir_ssa_def& ssa);
    189 
    190    unsigned get_ssa_register_index(const nir_ssa_def& ssa) const;
    191 
    192    unsigned get_local_register_index(const nir_register& reg);
    193 
    194    unsigned get_local_register_index(const nir_register& reg) const;
    195 
    196    void allocate_ssa_register(const nir_ssa_def& ssa);
    197 
    198    void allocate_array(const nir_register& reg);
    199 
    200 
    201    /** Allocate a register index with the given component mask.
    202     * If one of the components is already been allocated the function
    203     * will signal an error bz returning -1, otherwise a register index is
    204     * returned.
    205     */
    206    int allocate_with_mask(unsigned index, unsigned mask, bool pre_alloc);
    207 
    208    /** search for a new register with the given index in the
    209     * lookup map.
    210     * \param sel register sel value
    211     * \param swizzle register component, can also be 4,5, and 7
    212     * \param required true: in debug mode assert when register doesn't exist
    213     *                 false: return nullptr on failure
    214     */
    215 
    216    std::set<unsigned> m_ssa_undef;
    217 
    218    std::map<unsigned, unsigned> m_ssa_register_map;
    219 
    220    std::map<unsigned, PValue> m_registers;
    221 
    222    static PValue m_undef;
    223 
    224    struct VRec {
    225       unsigned index;
    226       unsigned mask;
    227       unsigned pre_alloc_mask;
    228    };
    229    std::map<unsigned, VRec> m_register_map;
    230 
    231    unsigned m_next_register_index;
    232 
    233 
    234    std::map<uint32_t, PValue> m_literals;
    235 
    236    int current_temp_reg_index;
    237    int next_temp_reg_comp;
    238 };
    239 
    240 }
    241 
    242 #endif // SFN_VALUEPOOL_H
    243