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 "unit_test.h"
17 #include "optimizer/analysis/liveness_analyzer.h"
18
19 namespace panda::compiler {
20 class LifeIntervalsTest : public CommonTest {
21 public:
LifeIntervalsTest()22 LifeIntervalsTest() : graph_(CreateEmptyGraph()) {}
23
Create(std::initializer_list<std::pair<LifeNumber,LifeNumber>> lns)24 LifeIntervals *Create(std::initializer_list<std::pair<LifeNumber, LifeNumber>> lns)
25 {
26 auto inst = graph_->CreateInstConstant(42);
27 auto li = GetAllocator()->New<LifeIntervals>(GetAllocator(), inst);
28 for (auto range = std::rbegin(lns); range != std::rend(lns); range++) {
29 li->AppendRange(range->first, range->second);
30 }
31 return li;
32 }
33
CheckSiblings(std::initializer_list<LifeIntervals * > intervals)34 void CheckSiblings(std::initializer_list<LifeIntervals *> intervals)
35 {
36 if (intervals.size() == 0) {
37 return;
38 }
39 for (auto it = std::begin(intervals); it != std::end(intervals); it++) {
40 auto next = std::next(it);
41 if (next == std::end(intervals)) {
42 ASSERT_EQ((*it)->GetSibling(), nullptr);
43 } else {
44 ASSERT_EQ((*it)->GetSibling(), *next);
45 }
46 }
47 }
48
CheckRanges(LifeIntervals * interval,std::initializer_list<std::pair<LifeNumber,LifeNumber>> ranges)49 void CheckRanges(LifeIntervals *interval, std::initializer_list<std::pair<LifeNumber, LifeNumber>> ranges)
50 {
51 ASSERT(interval != nullptr);
52 auto li_ranges = interval->GetRanges();
53 ASSERT_EQ(li_ranges.size(), ranges.size());
54
55 auto actual_it = li_ranges.begin();
56 auto expected_it = std::begin(ranges);
57 while (actual_it != li_ranges.end() && expected_it != std::end(ranges)) {
58 auto actual_range = *(actual_it++);
59 auto expected_lns = *(expected_it++);
60 ASSERT_EQ(actual_range.GetBegin(), expected_lns.first);
61 ASSERT_EQ(actual_range.GetEnd(), expected_lns.second);
62 }
63 }
64
65 private:
66 Graph *graph_;
67 };
68
TEST_F(LifeIntervalsTest,SplitAtTheEnd)69 TEST_F(LifeIntervalsTest, SplitAtTheEnd)
70 {
71 auto interval = Create({{0, 4}});
72 auto split = interval->SplitAt(4, GetAllocator());
73
74 CheckSiblings({interval, split});
75 CheckRanges(interval, {{0, 4}});
76 CheckRanges(split, {});
77 }
78
TEST_F(LifeIntervalsTest,SplitBetweenRanges)79 TEST_F(LifeIntervalsTest, SplitBetweenRanges)
80 {
81 auto interval = Create({{0, 4}, {8, 10}});
82 auto split = interval->SplitAt(6, GetAllocator());
83
84 CheckSiblings({interval, split});
85 CheckRanges(interval, {{0, 4}});
86 CheckRanges(split, {{8, 10}});
87 }
88
TEST_F(LifeIntervalsTest,SplitRange)89 TEST_F(LifeIntervalsTest, SplitRange)
90 {
91 auto interval = Create({{0, 10}});
92 auto split = interval->SplitAt(6, GetAllocator());
93
94 CheckSiblings({interval, split});
95 CheckRanges(interval, {{0, 6}});
96 CheckRanges(split, {{6, 10}});
97 }
98
TEST_F(LifeIntervalsTest,SplitIntervalWithMultipleRanges)99 TEST_F(LifeIntervalsTest, SplitIntervalWithMultipleRanges)
100 {
101 auto interval = Create({{0, 4}, {6, 10}, {12, 20}});
102 auto split = interval->SplitAt(8, GetAllocator());
103
104 CheckSiblings({interval, split});
105 CheckRanges(interval, {{0, 4}, {6, 8}});
106 CheckRanges(split, {{8, 10}, {12, 20}});
107 }
108
TEST_F(LifeIntervalsTest,RecursiveSplits)109 TEST_F(LifeIntervalsTest, RecursiveSplits)
110 {
111 auto interval = Create({{0, 100}});
112 auto split0 = interval->SplitAt(50, GetAllocator());
113 auto split1 = split0->SplitAt(75, GetAllocator());
114 auto split2 = interval->SplitAt(25, GetAllocator());
115
116 CheckSiblings({interval, split2, split0, split1});
117 CheckRanges(interval, {{0, 25}});
118 CheckRanges(split2, {{25, 50}});
119 CheckRanges(split0, {{50, 75}});
120 CheckRanges(split1, {{75, 100}});
121 }
122
TEST_F(LifeIntervalsTest,IntervalsCoverage)123 TEST_F(LifeIntervalsTest, IntervalsCoverage)
124 {
125 auto interval = Create({{0, 20}, {22, 40}, {42, 100}});
126 auto split0 = interval->SplitAt(21, GetAllocator());
127 auto split1 = split0->SplitAt(50, GetAllocator());
128
129 EXPECT_TRUE(interval->SplitCover(18));
130 EXPECT_FALSE(split0->SplitCover(18));
131 EXPECT_FALSE(split1->SplitCover(18));
132
133 EXPECT_FALSE(interval->SplitCover(42));
134 EXPECT_TRUE(split0->SplitCover(42));
135 EXPECT_FALSE(split1->SplitCover(42));
136 }
137
TEST_F(LifeIntervalsTest,FindSiblingAt)138 TEST_F(LifeIntervalsTest, FindSiblingAt)
139 {
140 auto interval = Create({{0, 20}, {22, 40}, {42, 100}});
141 auto split0 = interval->SplitAt(22, GetAllocator());
142 auto split1 = split0->SplitAt(50, GetAllocator());
143
144 EXPECT_EQ(interval->FindSiblingAt(0), interval);
145 EXPECT_EQ(interval->FindSiblingAt(20), interval);
146 EXPECT_EQ(interval->FindSiblingAt(39), split0);
147 EXPECT_EQ(interval->FindSiblingAt(51), split1);
148 EXPECT_EQ(interval->FindSiblingAt(21), nullptr);
149 }
150
TEST_F(LifeIntervalsTest,Intersects)151 TEST_F(LifeIntervalsTest, Intersects)
152 {
153 auto interval = Create({{6, 10}});
154
155 EXPECT_TRUE(interval->Intersects(LiveRange(0, 20)));
156 EXPECT_TRUE(interval->Intersects(LiveRange(6, 10)));
157 EXPECT_TRUE(interval->Intersects(LiveRange(0, 8)));
158 EXPECT_TRUE(interval->Intersects(LiveRange(8, 20)));
159 EXPECT_TRUE(interval->Intersects(LiveRange(7, 9)));
160
161 EXPECT_FALSE(interval->Intersects(LiveRange(0, 4)));
162 EXPECT_FALSE(interval->Intersects(LiveRange(12, 20)));
163 }
164
TEST_F(LifeIntervalsTest,IsSameLocation)165 TEST_F(LifeIntervalsTest, IsSameLocation)
166 {
167 auto graph = CreateEmptyGraph();
168 GRAPH(graph)
169 {
170 CONSTANT(0, 0);
171 CONSTANT(1, 42);
172
173 BASIC_BLOCK(2, -1)
174 {
175 INST(2, Opcode::Add).u64().Inputs(0, 1);
176 INST(3, Opcode::Return).u64().Inputs(2);
177 }
178 };
179
180 auto con0 = &INS(0);
181 auto con42 = &INS(1);
182 auto add = &INS(2);
183
184 std::vector<std::function<LifeIntervals *()>> factories = {
185 [&]() {
186 auto li = GetAllocator()->New<LifeIntervals>(GetAllocator(), add);
187 li->SetReg(0);
188 return li;
189 },
190 [&]() {
191 auto li = GetAllocator()->New<LifeIntervals>(GetAllocator(), add);
192 li->SetReg(1);
193 return li;
194 },
195 [&]() {
196 auto li = GetAllocator()->New<LifeIntervals>(GetAllocator(), add);
197 li->SetLocation(Location::MakeStackSlot(1));
198 return li;
199 },
200 [&]() {
201 auto li = GetAllocator()->New<LifeIntervals>(GetAllocator(), add);
202 li->SetLocation(Location::MakeStackSlot(2));
203 return li;
204 },
205 [&]() {
206 auto li = GetAllocator()->New<LifeIntervals>(GetAllocator(), con42);
207 li->SetLocation(Location::MakeConstant(0));
208 return li;
209 },
210 [&]() {
211 auto li = GetAllocator()->New<LifeIntervals>(GetAllocator(), con42);
212 li->SetLocation(Location::MakeConstant(1));
213 return li;
214 },
215 [&]() {
216 auto li = GetAllocator()->New<LifeIntervals>(GetAllocator(), con0);
217 if (graph->GetZeroReg() == INVALID_REG) {
218 ASSERT(graph->GetArch() != Arch::AARCH64);
219 li->SetReg(31);
220 } else {
221 li->SetReg(graph->GetZeroReg());
222 }
223 return li;
224 }};
225
226 for (size_t l1_idx = 0; l1_idx < factories.size(); l1_idx++) {
227 auto interval0 = factories[l1_idx]();
228 for (size_t l2_idx = 0; l2_idx < factories.size(); l2_idx++) {
229 auto interval1 = factories[l2_idx]();
230 bool same_settings = l1_idx == l2_idx;
231 EXPECT_EQ(same_settings, interval0->GetLocation() == interval1->GetLocation());
232 }
233 }
234 }
235
TEST_F(LifeIntervalsTest,LastUsageBefore)236 TEST_F(LifeIntervalsTest, LastUsageBefore)
237 {
238 auto interval = Create({{10, 100}});
239
240 ASSERT_EQ(INVALID_LIFE_NUMBER, interval->GetLastUsageBefore(100));
241
242 interval->AddUsePosition(12);
243 interval->AddUsePosition(50);
244 interval->AddUsePosition(60);
245
246 ASSERT_EQ(INVALID_LIFE_NUMBER, interval->GetLastUsageBefore(12));
247 ASSERT_EQ(12, interval->GetLastUsageBefore(13));
248 ASSERT_EQ(60, interval->GetLastUsageBefore(100));
249 }
250
251 } // namespace panda::compiler
252