1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef COMPILER_OPTIMIZER_OPTIMIZATIONS_REGALLOC_INTERFERENCE_GRAPH_H 17 #define COMPILER_OPTIMIZER_OPTIMIZATIONS_REGALLOC_INTERFERENCE_GRAPH_H 18 19 #include <algorithm> 20 #include <climits> 21 #include <iostream> 22 #include <unordered_set> 23 #include "compiler/optimizer/ir/constants.h" 24 #include "libpandabase/macros.h" 25 #include "libpandabase/utils/bit_utils.h" 26 #include "utils/arena_containers.h" 27 #include "utils/small_vector.h" 28 #include "compiler_logger.h" 29 30 namespace panda::compiler { 31 class LifeIntervals; 32 33 class ColorNode { 34 public: 35 // Special color saying that color not in free registers but should be used on mapping 36 static constexpr uint16_t NO_BIAS = 0xffff; 37 38 template <typename T> ColorNode(unsigned number,T alloc)39 ColorNode(unsigned number, T alloc) : cs_point_set_(alloc), number_(number), physical_(), fixed_() 40 { 41 } 42 GetNumber()43 unsigned GetNumber() const noexcept 44 { 45 return number_; 46 } 47 SetColor(Register color)48 void SetColor(Register color) noexcept 49 { 50 color_ = color; 51 } 52 GetColor()53 Register GetColor() const noexcept 54 { 55 return color_; 56 } 57 SetBias(uint16_t bias)58 void SetBias(uint16_t bias) noexcept 59 { 60 bias_ = bias; 61 } 62 HasBias()63 bool HasBias() const noexcept 64 { 65 return bias_ != NO_BIAS; 66 } 67 GetBias()68 uint16_t GetBias() const noexcept 69 { 70 return bias_; 71 } 72 Assign(LifeIntervals * life_intervals)73 void Assign(LifeIntervals *life_intervals) noexcept 74 { 75 life_intervals_ = life_intervals; 76 } 77 IsFixedColor()78 bool IsFixedColor() const noexcept 79 { 80 return fixed_; 81 } 82 IsPhysical()83 bool IsPhysical() const noexcept 84 { 85 return physical_; 86 } 87 SetFixedColor(Register color,bool is_physical)88 void SetFixedColor(Register color, bool is_physical) noexcept 89 { 90 fixed_ = true; 91 physical_ = is_physical; 92 SetColor(color); 93 } 94 GetLifeIntervals()95 LifeIntervals *GetLifeIntervals() const noexcept 96 { 97 return life_intervals_; 98 } 99 AddCallsite(LifeNumber point)100 void AddCallsite(LifeNumber point) noexcept 101 { 102 cs_point_set_.insert(point); 103 } 104 GetCallsiteIntersectCount()105 unsigned GetCallsiteIntersectCount() const noexcept 106 { 107 return cs_point_set_.size(); 108 } 109 110 private: 111 LifeIntervals *life_intervals_ = nullptr; 112 ArenaUnorderedSet<LifeNumber> cs_point_set_; 113 unsigned number_; 114 uint16_t bias_ = NO_BIAS; // Bias is a group of nodes for coalescing 115 Register color_ = INVALID_REG; 116 uint8_t physical_ : 1; 117 uint8_t fixed_ : 1; 118 }; 119 120 class GraphMatrix { 121 public: GraphMatrix(ArenaAllocator * alloc)122 explicit GraphMatrix(ArenaAllocator *alloc) : matrix_(alloc->Adapter()) {} SetCapacity(unsigned capacity)123 void SetCapacity(unsigned capacity) 124 { 125 capacity_ = RoundUp(capacity, sizeof(uintptr_t)); 126 matrix_.clear(); 127 matrix_.resize(capacity_ * capacity_); 128 } 129 130 bool AddEdge(unsigned a, unsigned b); 131 HasEdge(unsigned a,unsigned b)132 bool HasEdge(unsigned a, unsigned b) const 133 { 134 return matrix_[FindEdge(a, b)]; 135 } 136 137 bool AddAffinityEdge(unsigned a, unsigned b); 138 HasAffinityEdge(unsigned a,unsigned b)139 bool HasAffinityEdge(unsigned a, unsigned b) const 140 { 141 return matrix_[FindAffinityEdge(a, b)]; 142 } 143 GetCapacity()144 unsigned GetCapacity() const noexcept 145 { 146 return capacity_; 147 } 148 149 private: 150 template <typename T> OrderNodes(T & a,T & b)151 void OrderNodes(T &a, T &b) const noexcept 152 { 153 ASSERT(a < capacity_); 154 ASSERT(b < capacity_); 155 if (a < b) { 156 std::swap(a, b); 157 } 158 } 159 FindEdge(unsigned a,unsigned b)160 unsigned FindEdge(unsigned a, unsigned b) const 161 { 162 // Placement in lower triangulated adjacency matrix 163 OrderNodes(a, b); 164 return a * capacity_ + b; 165 } 166 FindAffinityEdge(unsigned a,unsigned b)167 unsigned FindAffinityEdge(unsigned a, unsigned b) const 168 { 169 // Placement in lower triangulated adjacency matrix 170 OrderNodes(a, b); 171 return b * capacity_ + a; 172 } 173 174 ArenaVector<bool> matrix_; 175 unsigned capacity_ = 0; 176 }; 177 178 using NodeVector = ArenaVector<ColorNode>; 179 180 // TODO (Evgeny.Erokhin): In Appel's book described usage of 2 structures in parallel to hold interference: 181 // one is for random checks (here is a matrix) and lists on adjacency for sequental access. It's worth to add! 182 class InterferenceGraph { 183 public: InterferenceGraph(ArenaAllocator * alloc)184 explicit InterferenceGraph(ArenaAllocator *alloc) : nodes_(alloc->Adapter()), matrix_(alloc) {} 185 ColorNode *AllocNode(); 186 GetNodes()187 NodeVector &GetNodes() noexcept 188 { 189 return nodes_; 190 } 191 GetNodes()192 const NodeVector &GetNodes() const noexcept 193 { 194 return nodes_; 195 } 196 GetNode(unsigned num)197 ColorNode &GetNode(unsigned num) 198 { 199 return nodes_[num]; 200 } 201 GetNode(unsigned num)202 const ColorNode &GetNode(unsigned num) const 203 { 204 return nodes_[num]; 205 } 206 Size()207 unsigned Size() const noexcept 208 { 209 return nodes_.size(); 210 } 211 212 void Reserve(size_t count); 213 214 struct Bias { 215 unsigned callsites = 0; 216 Register color = INVALID_REG; 217 }; 218 AddBias()219 Bias &AddBias() noexcept 220 { 221 return biases_.emplace_back(); 222 } 223 UpdateBiasData(Bias * bias,const ColorNode & node)224 void UpdateBiasData(Bias *bias, const ColorNode &node) 225 { 226 ASSERT(bias != nullptr); 227 if (node.GetColor() != INVALID_REG) { 228 bias->color = node.GetColor(); 229 } 230 bias->callsites += node.GetCallsiteIntersectCount(); 231 } 232 GetBiasCount()233 unsigned GetBiasCount() const noexcept 234 { 235 return biases_.size(); 236 } 237 238 void AddEdge(unsigned a, unsigned b); 239 bool HasEdge(unsigned a, unsigned b) const; 240 void AddAffinityEdge(unsigned a, unsigned b); 241 bool HasAffinityEdge(unsigned a, unsigned b) const; 242 243 // Build LexBFS, so reverse order gives minimal coloring 244 ArenaVector<unsigned> LexBFS() const; 245 246 bool IsChordal() const; 247 void Dump(const std::string &name = "IG", bool skip_physical = true, std::ostream &out = std::cout) const; 248 249 template <unsigned MAX_COLORS> AssignColors(size_t colors,size_t callee_offset)250 Register AssignColors(size_t colors, size_t callee_offset) 251 { 252 ASSERT(colors <= MAX_COLORS); 253 std::bitset<MAX_COLORS> nbr_colors; 254 std::bitset<MAX_COLORS> nbr_bias_colors; 255 Register max_color = 0; 256 257 for (unsigned id = 0; id < Size(); id++) { 258 auto &node = GetNode(id); 259 260 // Skip colored 261 if (node.GetColor() != INVALID_REG) { 262 continue; 263 } 264 265 // Make busy colors maps 266 MakeBusyBitmap(id, &nbr_colors, &nbr_bias_colors); 267 268 // Try bias color first if free 269 size_t try_color; 270 if (node.HasBias() && biases_[node.GetBias()].color != INVALID_REG && 271 !nbr_colors[biases_[node.GetBias()].color]) { 272 try_color = biases_[node.GetBias()].color; 273 COMPILER_LOG(DEBUG, REGALLOC) << "Bias color chosen " << try_color; 274 } else { 275 // The best case is to find color that is not in neighbour colors and not in biased 276 nbr_bias_colors |= nbr_colors; // Make compound busy bitmap 277 278 // For nodes that take part in bias with callsites intersection, prefer callee saved registers. 279 // In cases first interval of bias isn't intersected it will be placed in callersaved register, 280 // that will affect entire coalesced bias group. 281 size_t off = 0; 282 if (node.HasBias() && biases_[node.GetBias()].callsites > 0) { 283 off = callee_offset; 284 } 285 286 // Find first not allocated disregard biasing 287 if ((try_color = FirstFree(nbr_colors, nbr_bias_colors, colors, off)) == colors) { 288 return 0; // No colors left 289 } 290 291 // Assign bias color if first observed in component 292 if (node.HasBias() && biases_[node.GetBias()].color == INVALID_REG) { 293 biases_[node.GetBias()].color = try_color; 294 COMPILER_LOG(DEBUG, REGALLOC) << "Set bias color " << try_color; 295 } 296 } 297 298 // Assign color 299 node.SetColor(try_color); 300 COMPILER_LOG(DEBUG, REGALLOC) << "Node " << node.GetNumber() << ": Set color: " 301 << " " << unsigned(node.GetColor()); 302 max_color = std::max<Register>(try_color, max_color); 303 } 304 305 return max_color + 1; 306 } 307 308 private: 309 template <typename T> MakeBusyBitmap(unsigned id,T * nbr_colors,T * nbr_bias_colors)310 void MakeBusyBitmap(unsigned id, T *nbr_colors, T *nbr_bias_colors) 311 { 312 nbr_colors->reset(); 313 nbr_bias_colors->reset(); 314 // Collect neighbors colors 315 for (unsigned nbr_id = 0; nbr_id < Size(); nbr_id++) { 316 auto &nbr_node = GetNode(nbr_id); 317 318 // Collect neighbour color 319 if (nbr_node.GetColor() != INVALID_REG && HasEdge(id, nbr_id)) { 320 ASSERT(nbr_node.GetColor() < nbr_colors->size()); 321 nbr_colors->set(nbr_node.GetColor()); 322 } else if (nbr_id != id && nbr_node.HasBias() && HasEdge(id, nbr_id)) { 323 // Collect biased neighbour color 324 ASSERT(nbr_node.GetBias() < GetBiasCount()); 325 if (biases_[nbr_node.GetBias()].color != INVALID_REG) { 326 nbr_bias_colors->set(biases_[nbr_node.GetBias()].color); 327 } 328 } 329 } 330 } 331 332 template <typename T> FirstFree(const T & nbr_bs,const T & nbr_bs_bias,size_t colors,size_t off)333 static size_t FirstFree(const T &nbr_bs, const T &nbr_bs_bias, size_t colors, size_t off) 334 { 335 // Find first free 336 size_t try_color; 337 for (try_color = off; try_color < colors + off; try_color++) { 338 if (!nbr_bs[try_color % colors]) { 339 break; 340 } 341 } 342 343 // Find free regarding biasing (higher part of bitmap) 344 for (auto i = try_color; i < colors + off; i++) { 345 if (!nbr_bs_bias[i % colors]) { 346 try_color = i; 347 break; 348 } 349 } 350 351 return try_color == colors + off ? colors : try_color % colors; 352 } 353 354 NodeVector nodes_; 355 GraphMatrix matrix_; 356 static const size_t DEFAULT_BIAS_SIZE = 16; 357 SmallVector<Bias, DEFAULT_BIAS_SIZE> biases_; 358 }; 359 } // namespace panda::compiler 360 361 #endif // COMPILER_OPTIMIZER_OPTIMIZATIONS_REGALLOC_INTERFERENCE_GRAPH_H 362