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 LiveRangeEntryLiveRangeEntry52 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 printLiveRangeEntry60 void print(std::ostream& os) const { 61 os << *m_register << "(" << m_index << ", " << m_color << ") [" 62 << m_start << ":" << m_end << "]"; 63 } 64 }; 65 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()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 set_life_range(const Register & reg,int start,int end)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 component(int i)91 ChannelLiveRange& component(int i) { 92 return m_life_ranges[i]; 93 } 94 component(int i)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 RegisterKey(uint32_t index,uint32_t chan,EValuePool pool)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 print(std::ostream & os)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 { operatorregister_key_hash162 std::size_t operator () (const RegisterKey& key) const { 163 return key.hash; 164 } 165 }; 166 167 class ChannelCounts { 168 public: inc_count(int chan)169 void inc_count(int chan) {++m_counts[chan];} least_used()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 } print(std::ostream & os)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 next_register_index()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