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 <algorithm>
17 #include "liveness_analyzer.h"
18 #include "live_registers.h"
19
20 namespace panda::compiler {
21
22 namespace {
23 struct Split {
Splitpanda::compiler::__anon84cbb7b40111::Split24 Split(LifeIntervalsIt p_begin, LifeIntervalsIt p_end, LifeNumber p_min, LifeNumber p_max,
25 LifeIntervalsTreeNode *p_parent)
26 : begin(p_begin), end(p_end), min(p_min), max(p_max), parent(p_parent)
27 {
28 ASSERT(p_begin < p_end);
29 ASSERT(p_min <= p_max);
30 }
31 LifeIntervalsIt begin; // NOLINT(misc-non-private-member-variables-in-classes)
32 LifeIntervalsIt end; // NOLINT(misc-non-private-member-variables-in-classes)
33 LifeNumber min; // NOLINT(misc-non-private-member-variables-in-classes)
34 LifeNumber max; // NOLINT(misc-non-private-member-variables-in-classes)
35 LifeIntervalsTreeNode *parent; // NOLINT(misc-non-private-member-variables-in-classes)
36 };
37
38 // copy intervals with assigned registers and compute min and max life numbers covered by all these intervals
CopyIntervals(const ArenaVector<LifeIntervals * > & source,ArenaVector<LifeIntervals * > * destination)39 std::pair<LifeNumber, LifeNumber> CopyIntervals(const ArenaVector<LifeIntervals *> &source,
40 ArenaVector<LifeIntervals *> *destination)
41 {
42 LifeNumber min_ln = std::numeric_limits<LifeNumber>::max();
43 LifeNumber max_ln = 0;
44 for (auto &interval : source) {
45 for (auto split = interval; !interval->IsPhysical() && split != nullptr; split = split->GetSibling()) {
46 if (split->HasReg()) {
47 min_ln = std::min(min_ln, split->GetBegin());
48 max_ln = std::max(max_ln, split->GetEnd());
49 destination->push_back(split);
50 }
51 }
52 }
53 return std::make_pair(min_ln, max_ln);
54 }
55
PartitionLeftSplit(const LifeIntervalsIt & left,const LifeIntervalsIt & right,LifeNumber midpoint,LifeNumber * min_ln,LifeNumber * max_ln)56 LifeIntervalsIt PartitionLeftSplit(const LifeIntervalsIt &left, const LifeIntervalsIt &right, LifeNumber midpoint,
57 LifeNumber *min_ln, LifeNumber *max_ln)
58 {
59 LifeNumber left_min_ln = std::numeric_limits<LifeNumber>::max();
60 LifeNumber left_max_ln = 0;
61 auto result = std::partition(left, right, [&midpoint, &left_min_ln, &left_max_ln](const auto &em) {
62 if (em->GetEnd() < midpoint) {
63 left_min_ln = std::min(left_min_ln, em->GetBegin());
64 left_max_ln = std::max(left_max_ln, em->GetEnd());
65 return true;
66 }
67 return false;
68 });
69 *min_ln = left_min_ln;
70 *max_ln = left_max_ln;
71 return result;
72 }
73
PartitionRightSplit(const LifeIntervalsIt & left,const LifeIntervalsIt & right,LifeNumber midpoint,LifeNumber * min_ln,LifeNumber * max_ln)74 LifeIntervalsIt PartitionRightSplit(const LifeIntervalsIt &left, const LifeIntervalsIt &right, LifeNumber midpoint,
75 LifeNumber *min_ln, LifeNumber *max_ln)
76 {
77 LifeNumber right_min_ln = std::numeric_limits<LifeNumber>::max();
78 LifeNumber right_max_ln = 0;
79 auto result = std::partition(left, right, [&midpoint, &right_min_ln, &right_max_ln](const auto &em) {
80 if (em->GetBegin() > midpoint) {
81 right_min_ln = std::min(right_min_ln, em->GetBegin());
82 right_max_ln = std::max(right_max_ln, em->GetEnd());
83 return false;
84 }
85 return true;
86 });
87 *min_ln = right_min_ln;
88 *max_ln = right_max_ln;
89 return result;
90 }
91 } // namespace
92
BuildIntervalsTree(const ArenaVector<LifeIntervals * > & life_intervals,const Graph * graph)93 LifeIntervalsTree *LifeIntervalsTree::BuildIntervalsTree(const ArenaVector<LifeIntervals *> &life_intervals,
94 const Graph *graph)
95 {
96 auto alloc = graph->GetAllocator();
97 auto lalloc = graph->GetLocalAllocator();
98 auto intervals = alloc->New<ArenaVector<LifeIntervals *>>(alloc->Adapter());
99 ArenaQueue<const Split *> queue(lalloc->Adapter());
100
101 auto ln_range = CopyIntervals(life_intervals, intervals);
102 if (intervals->empty()) {
103 return nullptr;
104 }
105 queue.push(lalloc->New<Split>(intervals->begin(), intervals->end(), ln_range.first, ln_range.second, nullptr));
106
107 LifeIntervalsTreeNode *root {nullptr};
108
109 // Split each interval into three parts:
110 // 1) intervals covering mid point;
111 // 2) intervals ended before mid point;
112 // 3) intervals started after mid point.
113 // Allocate tree node for (1), recursively process (2) and (3).
114 while (!queue.empty()) {
115 auto split = queue.front();
116 queue.pop();
117 if (split->end - split->begin <= 0) {
118 continue;
119 }
120
121 auto midpoint = split->min + (split->max - split->min) / 2U;
122
123 LifeNumber left_min_ln;
124 LifeNumber left_max_ln;
125 auto left_midpoint = PartitionLeftSplit(split->begin, split->end, midpoint, &left_min_ln, &left_max_ln);
126
127 LifeNumber right_min_ln;
128 LifeNumber right_max_ln;
129 auto right_midpoint = PartitionRightSplit(left_midpoint, split->end, midpoint, &right_min_ln, &right_max_ln);
130
131 std::sort(left_midpoint, right_midpoint,
132 [](LifeIntervals *l, LifeIntervals *r) { return l->GetEnd() > r->GetEnd(); });
133
134 auto node = alloc->New<LifeIntervalsTreeNode>(split->min, split->max, left_midpoint, right_midpoint);
135 if (split->parent == nullptr) {
136 root = node;
137 } else if (split->parent->GetMidpoint() > midpoint) {
138 split->parent->SetLeft(node);
139 } else {
140 split->parent->SetRight(node);
141 }
142 if (split->begin < left_midpoint) {
143 queue.push(lalloc->New<Split>(split->begin, left_midpoint, left_min_ln, left_max_ln, node));
144 }
145 if (right_midpoint < split->end) {
146 queue.push(lalloc->New<Split>(right_midpoint, split->end, right_min_ln, right_max_ln, node));
147 }
148 }
149 return alloc->New<LifeIntervalsTree>(root);
150 }
151
152 } // namespace panda::compiler
153