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