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 #pragma once
28
29 #include "sfn_memorypool.h"
30 #include "sfn_alu_defines.h"
31 #include <memory>
32 #include <vector>
33 #include <iosfwd>
34 #include <map>
35 #include <set>
36 #include <array>
37 #include <cassert>
38
39 #if __cpp_exceptions >= 199711L
40 #include <exception>
41 #define ASSERT_OR_THROW(EXPR, ERROR) if (!(EXPR)) throw std::invalid_argument(ERROR)
42 #else
43 #define ASSERT_OR_THROW(EXPR, ERROR) if (!(EXPR)) unreachable(ERROR)
44 #endif
45
46 namespace r600 {
47
48 enum Pin {
49 pin_none,
50 pin_chan,
51 pin_array,
52 pin_group,
53 pin_chgr,
54 pin_fully,
55 pin_free
56 };
57
58 std::ostream& operator << (std::ostream& os, Pin pin);
59
60 class Register;
61 class RegisterVisitor;
62 class ConstRegisterVisitor;
63 class Instr;
64 class InlineConstant;
65 class LiteralConstant;
66 class UniformValue;
67
68 using InstructionSet = std::set<Instr *, std::less<Instr *>, Allocator<Instr *>>;
69
70 class VirtualValue : public Allocate {
71 public:
72
73 static const uint32_t virtual_register_base = 1024;
74 static const uint32_t clause_temp_registers = 2;
75 static const uint32_t gpr_register_end = 128 - 2 * clause_temp_registers;
76 static const uint32_t clause_temp_register_begin = gpr_register_end;
77 static const uint32_t clause_temp_register_end = 128;
78
79 static const uint32_t uniforms_begin = 512;
80 static const uint32_t uniforms_end = 640;
81
82 using Pointer = R600_POINTER_TYPE(VirtualValue);
83
84 VirtualValue(int sel, int chan, Pin pin);
85 VirtualValue(const VirtualValue& orig) = default;
86
sel()87 int sel() const { return m_sel; }
chan()88 int chan() const { return m_chan;}
pin()89 Pin pin() const { return m_pins;};
90 bool is_virtual() const;
91
set_pin(Pin p)92 void set_pin(Pin p) { m_pins = p;}
93
94
95 virtual void accept(RegisterVisitor& vistor) = 0;
96 virtual void accept(ConstRegisterVisitor& vistor) const = 0;
97 virtual void print(std::ostream& os) const = 0;
98
99 bool equal_to(const VirtualValue& other) const;
100 Pointer get_addr() const;
101
102 static Pointer from_string(const std::string& s);
103
as_register()104 virtual Register *as_register() { return nullptr;}
as_inline_const()105 virtual InlineConstant * as_inline_const() { return nullptr;}
as_literal()106 virtual LiteralConstant *as_literal() { return nullptr;}
as_uniform()107 virtual UniformValue *as_uniform() { return nullptr;}
108 virtual bool ready(int block, int index) const;
109
110 static constexpr char chanchar[9] = "xyzw01?_";
111
112 protected:
do_set_chan(int c)113 void do_set_chan(int c) {m_chan = c;}
set_sel_internal(int sel)114 void set_sel_internal(int sel) { m_sel = sel; }
115
116 private:
117 uint32_t m_sel;
118 int m_chan;
119 Pin m_pins;
120 };
121 using PVirtualValue = VirtualValue::Pointer;
122
123
124 inline std::ostream& operator << (std::ostream& os, const VirtualValue& val)
125 {
126 val.print(os);
127 return os;
128 }
129
130 inline bool operator == (const VirtualValue& lhs, const VirtualValue& rhs)
131 {
132 return lhs.equal_to(rhs);
133 }
134
135 struct LiveRange {
LiveRangeLiveRange136 LiveRange(): start(-1), end(-1), is_pinned(false) {}
LiveRangeLiveRange137 LiveRange(int s, int e): start(s), end(e), is_pinned(false) {}
138 int start;
139 int end;
140 int is_pinned;
141 };
142
143 class Register : public VirtualValue {
144 public:
145 using Pointer = R600_POINTER_TYPE(Register);
146
147 Register(int sel, int chan, Pin pin);
148 void accept(RegisterVisitor& vistor) override;
149 void accept(ConstRegisterVisitor& vistor) const override;
150 void print(std::ostream& os) const override;
151
live_start_pinned()152 int live_start_pinned() const { return m_pin_start;}
live_end_pinned()153 int live_end_pinned() const { return m_pin_end;}
154
155 void pin_live_range(bool start, bool end = false);
156
157 static Pointer from_string(const std::string& s);
158
as_register()159 Register *as_register() override { return this;}
160
161 void set_is_ssa(bool value);
162
is_ssa()163 bool is_ssa() const { return m_is_ssa;}
164
165 void add_parent(Instr *instr);
166 void del_parent(Instr *instr);
parents()167 const InstructionSet& parents() const {return m_parents;}
168
169 bool ready(int block, int index) const override;
170
uses()171 const InstructionSet& uses() const {return m_uses;}
172 void add_use(Instr *instr);
173 void del_use(Instr *instr);
has_uses()174 bool has_uses() const {return !m_uses.empty() || pin() == pin_array;}
set_chan(int c)175 void set_chan(int c) {do_set_chan(c);}
176
addr()177 virtual VirtualValue *addr() const { return nullptr;}
178
index()179 int index() const {return m_index;}
set_index(int idx)180 void set_index(int idx) {m_index = idx;}
181
set_sel(int new_sel)182 void set_sel(int new_sel) { set_sel_internal(new_sel); m_is_ssa = false;}
183
184 private:
185 Register(const Register& orig) = delete;
186 Register(const Register&& orig) = delete;
187 Register& operator = (const Register& orig) = delete;
188 Register& operator = (Register&& orig) = delete;
189
forward_del_use(Instr * instr)190 virtual void forward_del_use(Instr *instr) {(void)instr;}
forward_add_use(Instr * instr)191 virtual void forward_add_use(Instr *instr) {(void)instr;}
192 virtual void add_parent_to_array(Instr *instr);
193 virtual void del_parent_from_array(Instr *instr);
194
195 InstructionSet m_parents;
196 InstructionSet m_uses;
197
198 int m_index{-1};
199
200 bool m_is_ssa {false};
201 bool m_pin_start {false};
202 bool m_pin_end {false};
203 };
204 using PRegister = Register::Pointer;
205
206 inline std::ostream& operator << (std::ostream& os, const Register& val)
207 {
208 val.print(os);
209 return os;
210 }
211
212 class InlineConstant : public VirtualValue {
213 public:
214 using Pointer = R600_POINTER_TYPE(InlineConstant);
215
216 InlineConstant(int sel, int chan = 0);
217
218 void accept(RegisterVisitor& vistor) override;
219 void accept(ConstRegisterVisitor& vistor) const override;
220 void print(std::ostream& os) const override;
221 static Pointer from_string(const std::string& s);
222 static Pointer param_from_string(const std::string& s);
223
as_inline_const()224 InlineConstant * as_inline_const() override { return this;}
225 private:
226 InlineConstant(const InlineConstant& orig) = default;
227 static std::map<std::string, std::pair<AluInlineConstants, bool>> s_opmap;
228
229 };
230 using PInlineConstant = InlineConstant::Pointer;
231
232 inline std::ostream& operator << (std::ostream& os, const InlineConstant& val)
233 {
234 val.print(os);
235 return os;
236 }
237
238 class RegisterVec4 {
239 public:
240 using Swizzle = std::array<uint8_t, 4>;
241 RegisterVec4();
242 RegisterVec4(int sel, bool is_ssa = false, const Swizzle& swz = {0,1,2,3}, Pin pin = pin_group);
243 RegisterVec4(PRegister x, PRegister y, PRegister z, PRegister w, Pin pin);
244
245 RegisterVec4(const RegisterVec4& orig);
246
247 RegisterVec4(RegisterVec4&& orig) = default;
248 RegisterVec4& operator = (RegisterVec4& orig) = default;
249 RegisterVec4& operator = (RegisterVec4&& orig) = default;
250
251 void add_use(Instr *instr);
252 void del_use(Instr *instr);
253 bool has_uses() const;
254
255 int sel() const;
256 void print(std::ostream& os) const;
257
258 class Element : public Allocate {
259 public:
260 Element(const RegisterVec4& parent, int chan);
261 Element(const RegisterVec4& parent, PRegister value);
value()262 PRegister value() { return m_value; }
set_value(PRegister reg)263 void set_value(PRegister reg) { m_value = reg;}
264 private:
265 const RegisterVec4& m_parent;
266 PRegister m_value;
267 };
268
269 friend class Element;
270
271 PRegister operator [] (int i) const {
272 return m_values[i]->value();
273 }
274
275 PRegister operator [] (int i) {
276 return m_values[i]->value();
277 }
278
set_value(int i,PRegister reg)279 void set_value(int i, PRegister reg) {
280 assert(reg->sel() == m_sel);
281 m_swz[i] = reg->chan();
282 m_values[i]->set_value(reg);
283 }
284
285 bool ready(int block_id, int index) const;
286 private:
287 int m_sel;
288 Swizzle m_swz;
289 std::array<R600_POINTER_TYPE(Element), 4> m_values;
290 };
291
292 bool operator == (const RegisterVec4& lhs, const RegisterVec4& rhs);
293
294 inline bool operator != (const RegisterVec4& lhs, const RegisterVec4& rhs)
295 {
296 return !(lhs == rhs);
297 }
298
299 inline std::ostream& operator << (std::ostream& os, const RegisterVec4& val)
300 {
301 val.print(os);
302 return os;
303 }
304
305
306 class LiteralConstant : public VirtualValue {
307 public:
308 using Pointer = R600_POINTER_TYPE(LiteralConstant);
309
310 LiteralConstant(uint32_t value);
311 void accept(RegisterVisitor& vistor) override;
312 void accept(ConstRegisterVisitor& vistor) const override;
313 void print(std::ostream& os) const override;
value()314 uint32_t value() const {return m_value;}
315 static Pointer from_string(const std::string& s);
as_literal()316 LiteralConstant *as_literal() override { return this;}
317
318 private:
319 LiteralConstant(const LiteralConstant& orig) = default;
320 uint32_t m_value;
321 };
322 using PLiteralVirtualValue = LiteralConstant::Pointer;
323
324
325 class UniformValue : public VirtualValue {
326 public:
327 using Pointer = R600_POINTER_TYPE(UniformValue);
328
329 UniformValue(int sel, int chan, int kcache_bank = 0);
330 UniformValue(int sel, int chan, PVirtualValue buf_addr);
331
332 void accept(RegisterVisitor& vistor) override;
333 void accept(ConstRegisterVisitor& vistor) const override;
334 void print(std::ostream& os) const override;
kcache_bank()335 int kcache_bank() const { return m_kcache_bank; }
336 PVirtualValue buf_addr() const;
as_uniform()337 UniformValue *as_uniform() override { return this;}
338
339 bool equal_buf_and_cache(const UniformValue& other) const;
340 static Pointer from_string(const std::string& s);
341
342 private:
343 int m_kcache_bank;
344 PVirtualValue m_buf_addr;
345 };
346 using PUniformVirtualValue = UniformValue::Pointer;
347
348 inline std::ostream& operator << (std::ostream& os, const UniformValue& val)
349 {
350 val.print(os);
351 return os;
352 }
353
354 class LocalArrayValue;
355 class LocalArray : public Register {
356 public:
357 using Pointer = R600_POINTER_TYPE(LocalArray);
358 using Values = std::vector<LocalArrayValue *, Allocator<LocalArrayValue *> >;
359
360 LocalArray(int base_sel, int nchannels, int size, int frac = 0);
361 void accept(RegisterVisitor& vistor) override;
362 void accept(ConstRegisterVisitor& vistor) const override;
363 void print(std::ostream& os) const override;
364 bool ready_for_direct(int block, int index, int chan) const;
365 bool ready_for_indirect(int block, int index, int chan) const;
366
367 PRegister element(size_t offset, PVirtualValue indirect, uint32_t chan);
368
369 size_t size() const;
370 uint32_t nchannels() const;
frac()371 uint32_t frac() const { return m_frac;}
372
373 void add_parent_to_elements(Instr *instr);
374
375 const Register& operator ()(size_t idx, size_t chan) const;
376
begin()377 Values::iterator begin() { return m_values.begin();}
end()378 Values::iterator end() { return m_values.end();}
379
380 private:
381 uint32_t m_base_sel;
382 uint32_t m_nchannels;
383 size_t m_size;
384 Values m_values;
385 Values m_values_indirect;
386 int m_frac;
387 };
388
389 inline std::ostream& operator << (std::ostream& os, const LocalArray & val)
390 {
391 val.print(os);
392 return os;
393 }
394
395 class LocalArrayValue : public Register {
396 public:
397 using Pointer = R600_POINTER_TYPE(LocalArrayValue);
398
399 LocalArrayValue(PRegister reg, LocalArray& array);
400 LocalArrayValue(PRegister reg, PVirtualValue index, LocalArray &array);
401
402 void accept(RegisterVisitor& vistor) override;
403 void accept(ConstRegisterVisitor& vistor) const override;
404 void print(std::ostream& os) const override;
405 bool ready(int block, int index) const override;
406
407 VirtualValue *addr() const override;
408 const LocalArray& array() const;
409 private:
410 void forward_del_use(Instr *instr) override;
411 void forward_add_use(Instr *instr) override;
412 void add_parent_to_array(Instr *instr) override;
413 void del_parent_from_array(Instr *instr) override;
414
415 PVirtualValue m_addr;
416 LocalArray& m_array;
417 };
418
419 inline std::ostream& operator << (std::ostream& os, const LocalArrayValue& val)
420 {
421 val.print(os);
422 return os;
423 }
424
425 template <typename T>
sfn_value_equal(const T * lhs,const T * rhs)426 bool sfn_value_equal(const T* lhs, const T* rhs)
427 {
428 if (lhs) {
429 if (!rhs) return
430 false;
431 if ( !lhs->equal_to(*rhs))
432 return false;
433 } else {
434 if (rhs)
435 return false;
436 }
437 return true;
438 }
439
440 class RegisterVisitor {
441 public:
442 virtual void visit(Register& value) = 0;
443 virtual void visit(LocalArray& value) = 0;
444 virtual void visit(LocalArrayValue& value) = 0;
445 virtual void visit(UniformValue& value) = 0;
446 virtual void visit(LiteralConstant& value) = 0;
447 virtual void visit(InlineConstant& value) = 0;
448 };
449
450 class ConstRegisterVisitor {
451 public:
452 virtual void visit(const Register& value) = 0;
453 virtual void visit(const LocalArray& value) = 0;
454 virtual void visit(const LocalArrayValue& value) = 0;
455 virtual void visit(const UniformValue& value) = 0;
456 virtual void visit(const LiteralConstant& value) = 0;
457 virtual void visit(const InlineConstant& value) = 0;
458 };
459
460 }
461
462