• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mesa-c++  -*-
2  *
3  * Copyright (c) 2021 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 #ifndef VALUEFACTORY_H
28 #define VALUEFACTORY_H
29 
30 #include "nir.h"
31 #include "sfn_alu_defines.h"
32 #include "sfn_virtualvalues.h"
33 
34 #include <cassert>
35 #include <list>
36 #include <ostream>
37 #include <unordered_map>
38 
39 struct r600_shader;
40 
41 namespace r600 {
42 
43 struct LiveRangeEntry {
44    enum EUse {
45       use_export,
46       use_unspecified
47    };
48 
LiveRangeEntryLiveRangeEntry49    LiveRangeEntry(Register *reg):
50        m_register(reg)
51    {
52    }
53    int m_start{-1};
54    int m_end{-1};
55    int m_index{-1};
56    int m_color{-1};
57    bool m_alu_clause_local{false};
58    std::bitset<use_unspecified> m_use;
59    Register *m_register;
60 
printLiveRangeEntry61    void print(std::ostream& os) const
62    {
63       os << *m_register << "(" << m_index << ", " << m_color << ") [" << m_start << ":"
64          << m_end << "]";
65    }
66 };
67 
68 inline std::ostream&
69 operator<<(std::ostream& os, const LiveRangeEntry& lre)
70 {
71    lre.print(os);
72    return os;
73 }
74 
75 class LiveRangeMap {
76 public:
77    using ChannelLiveRange = std::vector<LiveRangeEntry>;
78 
operator()79    LiveRangeEntry& operator()(int index, int chan)
80    {
81       assert(chan < 4);
82       return m_life_ranges[chan].at(index);
83    }
84 
85    void append_register(Register *reg);
86 
set_life_range(const Register & reg,int start,int end)87    void set_life_range(const Register& reg, int start, int end)
88    {
89       auto& entry = m_life_ranges[reg.chan()].at(reg.index());
90       entry.m_start = start;
91       entry.m_end = end;
92    }
93 
94    std::array<size_t, 4> sizes() const;
95 
component(int i)96    ChannelLiveRange& component(int i) { return m_life_ranges[i]; }
97 
component(int i)98    const ChannelLiveRange& component(int i) const { return m_life_ranges[i]; }
99 
100 private:
101    std::array<ChannelLiveRange, 4> m_life_ranges;
102 };
103 
104 std::ostream&
105 operator<<(std::ostream& os, const LiveRangeMap& lrm);
106 
107 bool
108 operator==(const LiveRangeMap& lhs, const LiveRangeMap& rhs);
109 
110 inline bool
111 operator!=(const LiveRangeMap& lhs, const LiveRangeMap& rhs)
112 {
113    return !(lhs == rhs);
114 }
115 
116 enum EValuePool {
117    vp_ssa,
118    vp_register,
119    vp_temp,
120    vp_array,
121    vp_ignore
122 };
123 
124 union RegisterKey {
125    struct {
126       uint32_t index;
127       uint32_t chan : 29;
128       EValuePool pool : 3;
129    } value;
130    uint64_t hash;
131 
RegisterKey(uint32_t index,uint32_t chan,EValuePool pool)132    RegisterKey(uint32_t index, uint32_t chan, EValuePool pool)
133    {
134       value.index = index;
135       value.chan = chan;
136       value.pool = pool;
137    }
138 
print(std::ostream & os)139    void print(std::ostream& os) const
140    {
141       os << "(" << value.index << ", " << value.chan << ", ";
142       switch (value.pool) {
143       case vp_ssa:
144          os << "ssa";
145          break;
146       case vp_register:
147          os << "reg";
148          break;
149       case vp_temp:
150          os << "temp";
151          break;
152       case vp_array:
153          os << "array";
154          break;
155       case vp_ignore:
156          break;
157       }
158       os << ")";
159    }
160 };
161 
162 inline bool
163 operator==(const RegisterKey& lhs, const RegisterKey& rhs)
164 {
165    return lhs.hash == rhs.hash;
166 }
167 
168 inline std::ostream&
169 operator<<(std::ostream& os, const RegisterKey& key)
170 {
171    key.print(os);
172    return os;
173 }
174 
175 struct register_key_hash {
operatorregister_key_hash176    std::size_t operator()(const RegisterKey& key) const { return key.hash; }
177 };
178 
179 class ChannelCounts {
180 public:
inc_count(int chan)181    void inc_count(int chan) { ++m_counts[chan]; }
inc_count(int chan,int n)182    void inc_count(int chan, int n) { m_counts[chan] += n; }
least_used(uint8_t mask)183    int least_used(uint8_t mask) const
184    {
185       int least_used = 0;
186       uint32_t count = m_counts[0];
187       for (int i = 1; i < 4; ++i) {
188          if (!((1 << i) & mask))
189             continue;
190          if (count > m_counts[i]) {
191             count = m_counts[i];
192             least_used = i;
193          }
194       }
195       return least_used;
196    }
print(std::ostream & os)197    void print(std::ostream& os) const
198    {
199       os << "CC:" << m_counts[0] << " " << m_counts[1] << " " << m_counts[2] << " "
200          << m_counts[3];
201    }
202 
203 private:
204    std::array<uint32_t, 4> m_counts{0, 0, 0, 0};
205 };
206 
207 inline std::ostream&
208 operator<<(std::ostream& os, const ChannelCounts& cc)
209 {
210    cc.print(os);
211    return os;
212 }
213 
214 class ValueFactory : public Allocate {
215 public:
216    ValueFactory();
217 
218    void clear();
219 
220    ValueFactory(const ValueFactory& orig) = delete;
221    ValueFactory& operator=(const ValueFactory& orig) = delete;
222 
223    void set_virtual_register_base(int base);
224 
225    int new_register_index();
226 
227 
228    /* Allocate registers */
229    bool allocate_registers(const std::list<nir_intrinsic_instr *>& regs);
230    PRegister allocate_pinned_register(int sel, int chan);
231    RegisterVec4 allocate_pinned_vec4(int sel, bool is_ssa);
232 
233    /* Inject a predefined value for a given dest value
234     * (usually the result of a sysvalue load) */
235    void inject_value(const nir_def& def, int chan, PVirtualValue value);
236 
237    /* Get or create a destination value of vector of values */
238    PRegister
239    dest(const nir_def& def, int chan, Pin pin_channel, uint8_t chan_mask = 0xf);
240 
241    RegisterVec4 dest_vec4(const nir_def& dest, Pin pin);
242 
243    std::vector<PRegister, Allocator<PRegister>> dest_vec(const nir_def& dest,
244                                                          int num_components);
245 
246    PRegister dummy_dest(unsigned chan);
247 
248 
249    /* Create and get a temporary value */
250    PRegister temp_register(int pinned_channel = -1, bool is_ssa = true);
251    RegisterVec4 temp_vec4(Pin pin, const RegisterVec4::Swizzle& swizzle = {0, 1, 2, 3});
252 
253 
254    RegisterVec4
255    src_vec4(const nir_src& src, Pin pin, const RegisterVec4::Swizzle& swz = {0, 1, 2, 3});
256 
257    PVirtualValue src(const nir_alu_src& alu_src, int chan);
258    PVirtualValue src64(const nir_alu_src& alu_src, int chan, int comp);
259    PVirtualValue src(const nir_src& src, int chan);
260    PVirtualValue src(const nir_tex_src& tex_src, int chan);
261    PVirtualValue literal(uint32_t value);
262    PVirtualValue uniform(nir_intrinsic_instr *load_uniform, int chan);
263    PVirtualValue uniform(uint32_t index, int chan, int kcache);
264    std::vector<PVirtualValue, Allocator<PVirtualValue>> src_vec(const nir_src& src,
265                                                                 int components);
266 
267 
268    void allocate_const(nir_load_const_instr *load_const);
269 
270    PRegister dest_from_string(const std::string& s);
271    RegisterVec4 dest_vec4_from_string(const std::string& s,
272                                       RegisterVec4::Swizzle& swz,
273                                       Pin pin = pin_none);
274    PVirtualValue src_from_string(const std::string& s);
275    RegisterVec4 src_vec4_from_string(const std::string& s);
276 
277    LocalArray *array_from_string(const std::string& s);
278 
279 
280    PInlineConstant inline_const(AluInlineConstants sel, int chan);
281 
282    void get_shader_info(r600_shader *sh_info);
283 
284    PRegister undef(int index, int chan);
285    PVirtualValue zero();
286    PVirtualValue one();
287    PVirtualValue one_i();
288 
289    LiveRangeMap prepare_live_range_map();
290 
291    void clear_pins();
292 
next_register_index()293    int next_register_index() const { return m_next_register_index; }
array_registers()294    uint32_t array_registers() const { return m_required_array_registers; }
295 
296    PRegister addr();
297    PRegister idx_reg(unsigned idx);
298 
299 private:
300    PVirtualValue ssa_src(const nir_def& dest, int chan);
301 
302    int m_next_register_index;
303    int m_next_temp_channel{0};
304 
305    template <typename Key, typename T>
306    using unordered_map_alloc = std::unordered_map<Key,
307                                                   T,
308                                                   std::hash<Key>,
309                                                   std::equal_to<Key>,
310                                                   Allocator<std::pair<const Key, T>>>;
311 
312    template <typename Key, typename T>
313    using unordered_reg_map_alloc = std::unordered_map<Key,
314                                                       T,
315                                                       register_key_hash,
316                                                       std::equal_to<Key>,
317                                                       Allocator<std::pair<const Key, T>>>;
318 
319    using RegisterMap = unordered_reg_map_alloc<RegisterKey, PRegister>;
320    using ROValueMap = unordered_reg_map_alloc<RegisterKey, PVirtualValue>;
321 
322    RegisterMap m_registers;
323    std::list<PRegister, Allocator<PRegister>> m_pinned_registers;
324    ROValueMap m_values;
325    unordered_map_alloc<uint32_t, PLiteralVirtualValue> m_literal_values;
326    unordered_map_alloc<uint32_t, InlineConstant::Pointer> m_inline_constants;
327    unordered_map_alloc<uint32_t, uint32_t> m_ssa_index_to_sel;
328 
329    uint32_t m_nowrite_idx;
330 
331    RegisterVec4 m_dummy_dest_pinned{
332       g_registers_end, pin_chan, {0, 1, 2, 3}
333    };
334    ChannelCounts m_channel_counts;
335    uint32_t m_required_array_registers{0};
336 
337    AddressRegister *m_ar{nullptr};
338    AddressRegister *m_idx0{nullptr};
339    AddressRegister *m_idx1{nullptr};
340 };
341 
342 } // namespace r600
343 
344 #endif // VALUEFACTORY_H
345