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
46namespace r600 {
47
48enum Pin {
49   pin_none,
50   pin_chan,
51   pin_array,
52   pin_group,
53   pin_chgr,
54   pin_fully,
55   pin_free
56};
57
58std::ostream& operator << (std::ostream& os, Pin pin);
59
60class Register;
61class RegisterVisitor;
62class ConstRegisterVisitor;
63class Instr;
64class InlineConstant;
65class LiteralConstant;
66class UniformValue;
67
68using InstructionSet = std::set<Instr *, std::less<Instr *>,  Allocator<Instr *>>;
69
70class VirtualValue : public Allocate {
71public:
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
87   int sel() const { return m_sel; }
88   int chan() const { return m_chan;}
89   Pin pin() const { return m_pins;};
90   bool is_virtual() const;
91
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
104   virtual Register *as_register() { return nullptr;}
105   virtual InlineConstant * as_inline_const() { return nullptr;}
106   virtual LiteralConstant *as_literal() { return nullptr;}
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
112protected:
113   void do_set_chan(int c) {m_chan = c;}
114   void set_sel_internal(int sel) { m_sel = sel; }
115
116private:
117   uint32_t m_sel;
118   int m_chan;
119   Pin m_pins;
120};
121using PVirtualValue = VirtualValue::Pointer;
122
123
124inline std::ostream& operator << (std::ostream& os, const VirtualValue& val)
125{
126    val.print(os);
127    return os;
128}
129
130inline bool operator == (const VirtualValue& lhs, const VirtualValue& rhs)
131{
132    return lhs.equal_to(rhs);
133}
134
135struct LiveRange {
136   LiveRange(): start(-1), end(-1), is_pinned(false) {}
137   LiveRange(int s, int e): start(s), end(e), is_pinned(false) {}
138   int start;
139   int end;
140   int is_pinned;
141};
142
143class Register : public VirtualValue {
144public:
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
152    int live_start_pinned() const { return m_pin_start;}
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
159    Register *as_register() override { return this;}
160
161    void set_is_ssa(bool value);
162
163    bool is_ssa() const { return m_is_ssa;}
164
165    void add_parent(Instr *instr);
166    void del_parent(Instr *instr);
167    const InstructionSet& parents() const {return m_parents;}
168
169    bool ready(int block, int index) const override;
170
171    const InstructionSet& uses() const {return m_uses;}
172    void add_use(Instr *instr);
173    void del_use(Instr *instr);
174    bool has_uses() const {return !m_uses.empty() || pin() == pin_array;}
175    void set_chan(int c) {do_set_chan(c);}
176
177    virtual VirtualValue *addr() const { return nullptr;}
178
179    int index() const {return m_index;}
180    void set_index(int idx) {m_index = idx;}
181
182    void set_sel(int new_sel) { set_sel_internal(new_sel); m_is_ssa = false;}
183
184private:
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
190    virtual void forward_del_use(Instr *instr) {(void)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};
204using PRegister = Register::Pointer;
205
206inline std::ostream& operator << (std::ostream& os, const Register& val)
207{
208    val.print(os);
209    return os;
210}
211
212class InlineConstant : public VirtualValue {
213public:
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
224    InlineConstant * as_inline_const() override { return this;}
225private:
226    InlineConstant(const InlineConstant& orig) = default;
227    static std::map<std::string, std::pair<AluInlineConstants, bool>> s_opmap;
228
229};
230using PInlineConstant = InlineConstant::Pointer;
231
232inline std::ostream& operator << (std::ostream& os, const InlineConstant& val)
233{
234    val.print(os);
235    return os;
236}
237
238class RegisterVec4 {
239public:
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);
262      PRegister value() { return m_value; }
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
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;
286private:
287        int m_sel;
288        Swizzle m_swz;
289        std::array<R600_POINTER_TYPE(Element), 4> m_values;
290};
291
292bool operator == (const RegisterVec4& lhs, const RegisterVec4& rhs);
293
294inline bool operator != (const RegisterVec4& lhs, const RegisterVec4& rhs)
295{
296   return !(lhs == rhs);
297}
298
299inline std::ostream& operator << (std::ostream& os, const RegisterVec4& val)
300{
301    val.print(os);
302    return os;
303}
304
305
306class LiteralConstant : public VirtualValue {
307public:
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;
314   uint32_t value() const {return m_value;}
315   static Pointer from_string(const std::string& s);
316   LiteralConstant *as_literal() override { return this;}
317
318private:
319   LiteralConstant(const LiteralConstant& orig) = default;
320   uint32_t m_value;
321};
322using PLiteralVirtualValue = LiteralConstant::Pointer;
323
324
325class UniformValue : public VirtualValue {
326public:
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;
335   int kcache_bank() const { return m_kcache_bank; }
336   PVirtualValue buf_addr() const;
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
342private:
343   int m_kcache_bank;
344   PVirtualValue m_buf_addr;
345};
346using PUniformVirtualValue = UniformValue::Pointer;
347
348inline std::ostream& operator << (std::ostream& os, const UniformValue& val)
349{
350    val.print(os);
351    return os;
352}
353
354class LocalArrayValue;
355class LocalArray : public Register {
356public:
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;
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
377   Values::iterator begin() { return m_values.begin();}
378   Values::iterator end() { return m_values.end();}
379
380private:
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
389inline std::ostream& operator << (std::ostream& os, const LocalArray & val)
390{
391    val.print(os);
392    return os;
393}
394
395class LocalArrayValue : public Register {
396public:
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;
409private:
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
419inline std::ostream& operator << (std::ostream& os, const LocalArrayValue& val)
420{
421    val.print(os);
422    return os;
423}
424
425template <typename T>
426bool 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
440class RegisterVisitor {
441public:
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
450class ConstRegisterVisitor {
451public:
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