/* -*- mesa-c++ -*- * * Copyright (c) 2018 Collabora LTD * * Author: Gert Wollny * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * on the rights to use, copy, modify, merge, publish, distribute, sub * license, and/or sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef SFN_VALUEPOOL_H #define SFN_VALUEPOOL_H #include "sfn_value.h" #include "sfn_value_gpr.h" #include #include namespace r600 { using LiteralBuffer = std::map; class ValueMap { public: void insert(const PValue& v) { auto idx = index_from(v->sel(), v->chan()); m_map[idx] = v; } PValue get_or_inject(uint32_t index, uint32_t chan) { auto idx = index_from(index, chan); auto v = m_map.find(idx); if (v == m_map.end()) { insert(PValue(new GPRValue(index, chan))); v = m_map.find(idx); } return v->second; } std::map::const_iterator begin() const {return m_map.begin();} std::map::const_iterator end() const {return m_map.end();} private: uint32_t index_from(uint32_t index, uint32_t chan) { return (index << 3) + chan; } std::map m_map; }; /** \brief Class to keep track of registers, uniforms, and literals * This class holds the references to the uniforms and the literals * and is responsible for allocating the registers. */ class ValuePool { public: struct array_entry { unsigned index; unsigned length; unsigned ncomponents; bool operator ()(const array_entry& a, const array_entry& b) const { return a.length < b.length || (a.length == b.length && a.ncomponents > b.ncomponents); } }; using array_list = std::priority_queue, array_entry>; ValuePool(); GPRVector vec_from_nir(const nir_dest& dst, int num_components); std::vector varvec_from_nir(const nir_dest& src, int num_components); std::vector varvec_from_nir(const nir_src& src, int num_components); PValue from_nir(const nir_src& v, unsigned component, unsigned swizzled); PValue from_nir(const nir_src& v, unsigned component); /** Get a register that is used as source register in an ALU instruction * The PValue holds one componet as specified. If the register refers to * a GPR it must already have been allocated, uniforms and literals on * the other hand might be pre-loaded. */ PValue from_nir(const nir_alu_src& v, unsigned component); /** Get a register that is used as source register in an Texture instruction * The PValue holds one componet as specified. */ PValue from_nir(const nir_tex_src& v, unsigned component); /** Allocate a register that is used as destination register in an ALU * instruction. The PValue holds one componet as specified. */ PValue from_nir(const nir_alu_dest& v, unsigned component); /** Allocate a register that is used as destination register in any * instruction. The PValue holds one componet as specified. */ PValue from_nir(const nir_dest& v, unsigned component); /** Get the register index mapped from the NIR code to the r600 ir * \param index NIR index of register * \returns r600 ir inxex */ int lookup_register_index(const nir_src& src) const; /** Get the register index mapped from the NIR code to the r600 ir * \param index NIR index of register * \returns r600 ir inxex */ int lookup_register_index(const nir_dest& dst); /** Inject a register into a given ssa index position * This is used to redirect loads from system values and vertex attributes * that are already loaded into registers */ bool inject_register(unsigned sel, unsigned swizzle, const PValue ®, bool map); /** Reserve space for a local register */ void allocate_local_register(const nir_register& reg); void allocate_local_register(const nir_register ®, array_list& arrays); void allocate_arrays(array_list& arrays); void increment_reserved_registers() { ++m_next_register_index; } void set_reserved_registers(unsigned rr) { m_next_register_index =rr; } /** Allocate a register that is is needed for lowering an instruction * that requires complex calculations, */ int allocate_temp_register(); /** Reserve a undef register, currently it uses (0,7), * \todo should be eliminated in the final pass */ bool create_undef(nir_ssa_undef_instr* instr); /** Create a new register with the given index and store it in the * lookup map */ PValue create_register_from_nir_src(const nir_src& sel, int comp); ValueMap get_temp_registers() const; PValue lookup_register(unsigned sel, unsigned swizzle, bool required); size_t register_count() const {return m_next_register_index;} PValue create_register(unsigned index, unsigned swizzle); unsigned get_dst_ssa_register_index(const nir_ssa_def& ssa); PValue literal(uint32_t value); PGPRValue get_temp_register(int channel = -1); GPRVector get_temp_vec4(); private: unsigned get_ssa_register_index(const nir_ssa_def& ssa) const; unsigned get_local_register_index(const nir_register& reg); unsigned get_local_register_index(const nir_register& reg) const; void allocate_ssa_register(const nir_ssa_def& ssa); void allocate_array(const nir_register& reg); /** Allocate a register index with the given component mask. * If one of the components is already been allocated the function * will signal an error bz returning -1, otherwise a register index is * returned. */ int allocate_with_mask(unsigned index, unsigned mask, bool pre_alloc); /** Allocate a register index with the given component. * If the component is already been allocated the function * will signal an error bz returning -1, otherwise a register index is * returned. */ int allocate_component(unsigned index, unsigned comp, bool pre_alloc); /** search for a new register with the given index in the * lookup map. * \param sel register sel value * \param swizzle register component, can also be 4,5, and 7 * \param required true: in debug mode assert when register doesn't exist * false: return nullptr on failure */ std::set m_ssa_undef; std::map m_local_register_map; std::map m_ssa_register_map; std::map m_registers; static PValue m_undef; struct VRec { unsigned index; unsigned mask; unsigned pre_alloc_mask; }; std::map m_register_map; unsigned m_next_register_index; std::map m_arrays_map; std::map m_literals; int current_temp_reg_index; int next_temp_reg_comp; }; } #endif // SFN_VALUEPOOL_H