• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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