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