1/* -*- mesa-c++  -*-
2 *
3 * Copyright (c) 2018 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
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
37namespace r600 {
38
39using LiteralBuffer = std::map<unsigned, const nir_load_const_instr *>;
40
41class ValueMap {
42public:
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
59private:
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 */
70class ValuePool
71{
72public:
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
163protected:
164   std::vector<PGPRArray> m_reg_arrays;
165
166private:
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