• 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 #include "interference_graph.h"
17 #include <array>
18 #include <iterator>
19 #include <numeric>
20 #include "optimizer/analysis/liveness_analyzer.h"
21 #include "utils/small_vector.h"
22 
23 namespace panda::compiler {
AddEdge(unsigned a,unsigned b)24 bool GraphMatrix::AddEdge(unsigned a, unsigned b)
25 {
26     auto it = matrix_.begin() + FindEdge(a, b);
27     bool old_val = *it;
28     *it = true;
29     return old_val;
30 }
31 
AddAffinityEdge(unsigned a,unsigned b)32 bool GraphMatrix::AddAffinityEdge(unsigned a, unsigned b)
33 {
34     auto it = matrix_.begin() + FindAffinityEdge(a, b);
35     bool old_val = *it;
36     *it = true;
37     return old_val;
38 }
39 
40 // -------------------------------------------------------
41 
AllocNode()42 ColorNode *InterferenceGraph::AllocNode()
43 {
44     unsigned cur = nodes_.size();
45     nodes_.emplace_back(cur, nodes_.get_allocator());
46 
47     // Check matrix capacity
48     ASSERT(nodes_.size() <= matrix_.GetCapacity());
49 
50     return &nodes_.back();
51 }
52 
Reserve(size_t count)53 void InterferenceGraph::Reserve(size_t count)
54 {
55     nodes_.clear();
56     nodes_.reserve(count);
57     matrix_.SetCapacity(count);
58     biases_.clear();
59 }
60 
AddEdge(unsigned a,unsigned b)61 void InterferenceGraph::AddEdge(unsigned a, unsigned b)
62 {
63     matrix_.AddEdge(a, b);
64 }
65 
HasEdge(unsigned a,unsigned b) const66 bool InterferenceGraph::HasEdge(unsigned a, unsigned b) const
67 {
68     return matrix_.HasEdge(a, b);
69 }
70 
AddAffinityEdge(unsigned a,unsigned b)71 void InterferenceGraph::AddAffinityEdge(unsigned a, unsigned b)
72 {
73     matrix_.AddAffinityEdge(a, b);
74 }
75 
HasAffinityEdge(unsigned a,unsigned b) const76 bool InterferenceGraph::HasAffinityEdge(unsigned a, unsigned b) const
77 {
78     return matrix_.HasAffinityEdge(a, b);
79 }
80 
81 namespace {
82 constexpr size_t MIN_SIMPLITIAL_NODES = 3;
83 constexpr size_t DEFAULT_BOUNDARY_STACK = 16;
84 }  // namespace
85 
LexBFS() const86 ArenaVector<unsigned> InterferenceGraph::LexBFS() const
87 {
88     // Initialize out to sequentaly from 0
89     unsigned num = nodes_.size();
90     ArenaVector<unsigned> out(num, nodes_.get_allocator());
91     std::iota(out.begin(), out.end(), 0);
92 
93     // Less then 3 are all simplicial
94     if (out.size() < MIN_SIMPLITIAL_NODES) {
95         return out;
96     }
97 
98     // Control sub-sequences boundaries in stack maner
99     SmallVector<unsigned, DEFAULT_BOUNDARY_STACK> boundary_stack;
100     boundary_stack.reserve(num);
101     boundary_stack.push_back(num);  // Sentinel
102     unsigned pos = 0;               // Initialy we have set S of all elements
103 
104     while (true) {
105         ASSERT(pos < out.size());
106         auto id = out[pos];
107         pos++;
108 
109         // Check for boundaries colapse
110         ASSERT(!boundary_stack.empty());
111         auto prev_end = boundary_stack.back();
112         ASSERT(pos <= prev_end);
113         if (pos == prev_end) {
114             if (pos == num) {
115                 break;
116             }
117             boundary_stack.resize(boundary_stack.size() - 1);
118             ASSERT(!boundary_stack.empty());
119             prev_end = boundary_stack.back();
120         }
121 
122         // Partition on 2 groups: adjacent and not adjacent(last)
123         ASSERT(pos <= prev_end);
124         auto it = std::stable_partition(out.begin() + pos, out.begin() + prev_end,
125                                         [id, &out, this](unsigned val) { return HasEdge(id, out[val]); });
126         auto pivot = static_cast<unsigned>(std::distance(out.begin(), it));
127         // Split group if needed
128         if (pivot > pos && pivot != prev_end) {
129             boundary_stack.push_back(pivot);
130         }
131     }
132 
133     return out;
134 }
135 
136 namespace {
137 constexpr size_t DEFAULT_VECTOR_SIZE = 64;
138 }  // namespace
139 
IsChordal() const140 bool InterferenceGraph::IsChordal() const
141 {
142     const auto &peo = LexBFS();
143     SmallVector<Register, DEFAULT_VECTOR_SIZE> processed_nbr;
144 
145     for (size_t i = 0; i < peo.size(); i++) {
146         processed_nbr.clear();
147 
148         // Collect processed neighbors
149         for (size_t j = 0; j < i; j++) {
150             if (HasEdge(peo[i], peo[j])) {
151                 processed_nbr.push_back(j);
152             }
153         }
154 
155         // Check that all processed neighbors in clique
156         for (auto nbr1 : processed_nbr) {
157             for (auto nbr2 : processed_nbr) {
158                 if (nbr1 != nbr2 && !HasEdge(peo[nbr1], peo[nbr2])) {
159                     return false;
160                 }
161             }
162         }
163     }
164 
165     return true;
166 }
167 
168 namespace {
GetNodeShape(const InterferenceGraph & ig,unsigned i)169 const char *GetNodeShape(const InterferenceGraph &ig, unsigned i)
170 {
171     const char *shape = "ellipse";
172     if (ig.GetNode(i).IsPhysical()) {
173         shape = "box";
174     } else {
175         for (unsigned j = 0; j < ig.Size(); j++) {
176             if (i != j && ig.HasEdge(i, j) && ig.GetNode(j).IsPhysical()) {
177                 shape = "hexagon";
178                 break;
179             }
180         }
181     }
182     return shape;
183 }
184 }  // namespace
185 
Dump(const std::string & name,bool skip_physical,std::ostream & out) const186 void InterferenceGraph::Dump(const std::string &name, bool skip_physical, std::ostream &out) const
187 {
188     auto transformed_name = name;
189     std::replace(transformed_name.begin(), transformed_name.end(), ':', '_');
190     out << "Nodes: " << Size() << "\n\n"
191         << "\ngraph " << transformed_name << " {\nnode [colorscheme=spectral9]\n";
192     auto size = Size();
193     if (size == 0) {
194         out << "}\n";
195         return;
196     }
197 
198     // Map to colors
199     std::array<Register, std::numeric_limits<Register>::max()> colors {};
200     colors.fill(INVALID_REG);
201     Register cur_color = 0;
202 
203     for (auto &node : GetNodes()) {
204         if (!(skip_physical && node.IsPhysical()) && colors[node.GetColor()] == INVALID_REG) {
205             colors[node.GetColor()] = cur_color;
206             cur_color++;
207         }
208     }
209 
210     // Print header
211     for (unsigned i = 0; i < size; i++) {
212         if (skip_physical && GetNode(i).IsPhysical()) {
213             continue;
214         }
215         auto color = GetNode(i).GetColor();
216         out << i << " [color=" << unsigned(colors[color]) << ", xlabel=\"";
217         out << unsigned(color) << "\", tooltip=\"" << GetNode(i).GetLifeIntervals()->ToString<true>();
218         out << "\", shape=\"" << GetNodeShape(*this, i) << "\"]\n";
219     }
220 
221     auto edge_printer = [this, &out, skip_physical](auto node_num) {
222         for (unsigned j = 0; j < node_num; j++) {
223             if (!(skip_physical && GetNode(j).IsPhysical()) && HasEdge(node_num, j)) {
224                 if (GetNode(node_num).GetColor() == GetNode(j).GetColor() &&
225                     GetNode(node_num).GetColor() != INVALID_REG) {
226                     out << "Error: Same color\n";
227                 }
228                 out << node_num << "--" << j << "\n";
229             }
230         }
231     };
232 
233     // Print edges
234     for (unsigned i = 1; i < size; i++) {
235         if (skip_physical && GetNode(i).IsPhysical()) {
236             continue;
237         }
238         edge_printer(i);
239     }
240 
241     out << "}\n";
242 }
243 }  // namespace panda::compiler
244