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