• 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 <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