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