1 /*
2 * Copyright (c) 2021-2024 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/bounds_analysis.h"
18 #include "optimizer/optimizations/cleanup.h"
19 #include "optimizer/optimizations/peepholes.h"
20 #include "utils/arena_containers.h"
21
22 namespace ark::compiler {
23 class BoundsAnalysisTest : public CommonTest {
24 public:
BoundsAnalysisTest()25 BoundsAnalysisTest() : graph_(CreateGraphStartEndBlocks()) {}
26
GetGraph()27 Graph *GetGraph()
28 {
29 return graph_;
30 }
31
32 // ll, lr, rl, rr - test bounds
33 // rll, rlr, rrl, rrr - result bounds
CCTest(ConditionCode cc,BoundsRange l,BoundsRange r,BoundsRange rl,BoundsRange rr)34 void CCTest(ConditionCode cc, BoundsRange l, BoundsRange r, BoundsRange rl, BoundsRange rr)
35 {
36 auto [nrl, nrr] = BoundsRange::TryNarrowBoundsByCC(cc, {l, r});
37 ASSERT_EQ(nrl.GetLeft(), rl.GetLeft());
38 ASSERT_EQ(nrl.GetRight(), rl.GetRight());
39 ASSERT_EQ(nrr.GetLeft(), rr.GetLeft());
40 ASSERT_EQ(nrr.GetRight(), rr.GetRight());
41 }
42
43 using BR = BoundsRange;
44
45 void TypeFittingBuildGraph();
46
47 private:
48 Graph *graph_ {nullptr};
49 };
50 // NOLINTBEGIN(readability-magic-numbers)
TEST_F(BoundsAnalysisTest,NegTest)51 TEST_F(BoundsAnalysisTest, NegTest)
52 {
53 BoundsRange r1 = BoundsRange(-1L, 5U);
54 BoundsRange res1 = r1.Neg();
55 EXPECT_EQ(res1.GetLeft(), -5L);
56 EXPECT_EQ(res1.GetRight(), 1U);
57
58 BoundsRange r2 = BoundsRange(1U, 5U);
59 BoundsRange res2 = r2.Neg();
60 EXPECT_EQ(res2.GetLeft(), -5L);
61 EXPECT_EQ(res2.GetRight(), -1L);
62
63 BoundsRange r3 = BoundsRange(-5L, -1L);
64 BoundsRange res3 = r3.Neg();
65 EXPECT_EQ(res3.GetLeft(), 1U);
66 EXPECT_EQ(res3.GetRight(), 5U);
67 }
68
TEST_F(BoundsAnalysisTest,AbsTest)69 TEST_F(BoundsAnalysisTest, AbsTest)
70 {
71 BoundsRange r1 = BoundsRange(1U, 5U);
72 BoundsRange res1 = r1.Abs();
73 EXPECT_EQ(res1.GetLeft(), 1U);
74 EXPECT_EQ(res1.GetRight(), 5U);
75
76 BoundsRange r2 = BoundsRange(-5L, -1L);
77 BoundsRange res2 = r2.Abs();
78 EXPECT_EQ(res2.GetLeft(), 1U);
79 EXPECT_EQ(res2.GetRight(), 5U);
80
81 BoundsRange r3 = BoundsRange(-1L, 5U);
82 BoundsRange res3 = r3.Abs();
83 EXPECT_EQ(res3.GetLeft(), 0U);
84 EXPECT_EQ(res3.GetRight(), 5U);
85
86 BoundsRange r4 = BoundsRange(-10L, 5U);
87 BoundsRange res4 = r4.Abs();
88 EXPECT_EQ(res4.GetLeft(), 0U);
89 EXPECT_EQ(res4.GetRight(), 10U);
90 }
91
TEST_F(BoundsAnalysisTest,MulTest)92 TEST_F(BoundsAnalysisTest, MulTest)
93 {
94 BoundsRange r1 = BoundsRange(-7L, 5U);
95 BoundsRange r2 = BoundsRange(9U, 13U);
96 BoundsRange r3 = BoundsRange(2U, 5U);
97 BoundsRange r4 = BoundsRange(-4L, -1L);
98 BoundsRange r5 = BoundsRange(-5L, -2L);
99 BoundsRange r6 = BoundsRange(1U, 4U);
100
101 // All posible variations for GetLeft and GetRight
102 BoundsRange res = r1.Mul(r1);
103 EXPECT_EQ(res.GetLeft(), -7L * 5L); // min = ll * rr
104 EXPECT_EQ(res.GetRight(), -7L * -7L); // max = ll * rl
105
106 res = r2.Mul(r2);
107 EXPECT_EQ(res.GetLeft(), 9U * 9U); // min = ll * rl
108 EXPECT_EQ(res.GetRight(), 13U * 13U); // max = lr * rr
109
110 res = r3.Mul(r4);
111 EXPECT_EQ(res.GetLeft(), 5L * -4L); // min = lr * rl
112 EXPECT_EQ(res.GetRight(), 2L * -1L); // max = ll * rr
113
114 res = r4.Mul(r5);
115 EXPECT_EQ(res.GetLeft(), -1L * -2L); // min = lr * rr
116 EXPECT_EQ(res.GetRight(), -4L * -5L); // max = ll * rl
117
118 res = r5.Mul(r6);
119 EXPECT_EQ(res.GetLeft(), -5L * 4L); // min = ll * rr
120 EXPECT_EQ(res.GetRight(), -2L * 1L); // max = lr * rl
121 }
122
TEST_F(BoundsAnalysisTest,DivTest)123 TEST_F(BoundsAnalysisTest, DivTest)
124 {
125 auto l1 = BoundsRange(-7L, 5U);
126 auto l2 = BoundsRange(5U, 7U);
127 auto l3 = BoundsRange(-7L, -5L);
128 auto r1 = BoundsRange(2U);
129 auto r2 = BoundsRange(-2L);
130 BoundsRange res;
131
132 res = l1.Div(r1);
133 EXPECT_EQ(res.GetLeft(), -3L);
134 EXPECT_EQ(res.GetRight(), 2U);
135 res = l1.Div(r2);
136 EXPECT_EQ(res.GetLeft(), -2L);
137 EXPECT_EQ(res.GetRight(), 3U);
138
139 res = l2.Div(r1);
140 EXPECT_EQ(res.GetLeft(), 2U);
141 EXPECT_EQ(res.GetRight(), 3U);
142 res = l2.Div(r2);
143 EXPECT_EQ(res.GetLeft(), -3L);
144 EXPECT_EQ(res.GetRight(), -2L);
145
146 res = l3.Div(r1);
147 EXPECT_EQ(res.GetLeft(), -3L);
148 EXPECT_EQ(res.GetRight(), -2L);
149 res = l3.Div(r2);
150 EXPECT_EQ(res.GetLeft(), 2U);
151 EXPECT_EQ(res.GetRight(), 3U);
152 }
153
TEST_F(BoundsAnalysisTest,OverflowTest)154 TEST_F(BoundsAnalysisTest, OverflowTest)
155 {
156 ASSERT_EQ(BoundsRange::AddWithOverflowCheck(INT64_MAX, INT64_MAX), std::nullopt);
157 ASSERT_EQ(BoundsRange::AddWithOverflowCheck(INT64_MAX, 1U), std::nullopt);
158 ASSERT_EQ(BoundsRange::AddWithOverflowCheck(1U, INT64_MAX), std::nullopt);
159 ASSERT_EQ(BoundsRange::AddWithOverflowCheck(INT64_MIN, INT64_MIN), std::nullopt);
160 ASSERT_EQ(BoundsRange::AddWithOverflowCheck(INT64_MIN, -1L), std::nullopt);
161 ASSERT_EQ(BoundsRange::AddWithOverflowCheck(-1L, INT64_MIN), std::nullopt);
162
163 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(0U, INT64_MAX), 0U);
164 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(INT64_MAX, 0U), 0U);
165 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(0U, INT64_MIN), 0U);
166 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(INT64_MIN, 0U), 0U);
167
168 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(INT64_MAX, INT64_MAX), std::nullopt);
169 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(INT64_MAX, 2U), std::nullopt);
170 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(INT64_MIN, INT64_MIN), std::nullopt);
171 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(INT64_MIN, -2L), std::nullopt);
172 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(INT64_MAX, INT64_MIN), std::nullopt);
173 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(INT64_MAX, -2L), std::nullopt);
174 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(INT64_MIN, INT64_MAX), std::nullopt);
175 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(INT64_MIN, 2U), std::nullopt);
176
177 ASSERT_EQ(BoundsRange::DivWithOverflowCheck(INT64_MIN, -1L), std::nullopt);
178
179 ASSERT_EQ(BoundsRange::AddWithOverflowCheck(UINT64_MAX, UINT64_MAX), std::nullopt);
180 ASSERT_EQ(BoundsRange::AddWithOverflowCheck(UINT64_MAX, 1U), std::nullopt);
181 ASSERT_EQ(BoundsRange::AddWithOverflowCheck(1U, UINT64_MAX), std::nullopt);
182 ASSERT_NE(BoundsRange::AddWithOverflowCheck(UINT64_MAX / 2U, UINT64_MAX / 2U), std::nullopt);
183 ASSERT_NE(BoundsRange::AddWithOverflowCheck(UINT64_MAX - 1U, 1U), std::nullopt);
184 ASSERT_NE(BoundsRange::AddWithOverflowCheck(1U, UINT64_MAX - 1U), std::nullopt);
185
186 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(0U, UINT64_MAX), 0U);
187 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(UINT64_MAX, 0U), 0U);
188
189 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(UINT64_MAX, UINT64_MAX), std::nullopt);
190 ASSERT_EQ(BoundsRange::MulWithOverflowCheck(UINT64_MAX / 2U + 1, 2U), std::nullopt);
191 ASSERT_NE(BoundsRange::MulWithOverflowCheck(UINT64_MAX / 2U, 2U), std::nullopt);
192 }
193
TEST_F(BoundsAnalysisTest,BoundsNarrowing1)194 TEST_F(BoundsAnalysisTest, BoundsNarrowing1)
195 {
196 // case 1
197 CCTest(ConditionCode::CC_GT, BR(10U, 50U), BR(20U, 60U), BR(21U, 50U), BR(20U, 49U));
198 CCTest(ConditionCode::CC_A, BR(10U, 50U), BR(20U, 60U), BR(21U, 50U), BR(20U, 49U));
199 CCTest(ConditionCode::CC_GE, BR(10U, 50U), BR(20U, 60U), BR(20U, 50U), BR(20U, 50U));
200 CCTest(ConditionCode::CC_AE, BR(10U, 50U), BR(20U, 60U), BR(20U, 50U), BR(20U, 50U));
201 CCTest(ConditionCode::CC_LT, BR(10U, 50U), BR(20U, 60U), BR(10U, 50U), BR(20U, 60U));
202 CCTest(ConditionCode::CC_B, BR(10U, 50U), BR(20U, 60U), BR(10U, 50U), BR(20U, 60U));
203 CCTest(ConditionCode::CC_LE, BR(10U, 50U), BR(20U, 60U), BR(10U, 50U), BR(20U, 60U));
204 CCTest(ConditionCode::CC_BE, BR(10U, 50U), BR(20U, 60U), BR(10U, 50U), BR(20U, 60U));
205 CCTest(ConditionCode::CC_EQ, BR(10U, 50U), BR(20U, 60U), BR(20U, 50U), BR(20U, 50U));
206 CCTest(ConditionCode::CC_NE, BR(10U, 50U), BR(20U, 60U), BR(10U, 50U), BR(20U, 60U));
207
208 // case 2
209 CCTest(ConditionCode::CC_GT, BR(10U, 20U), BR(50U, 60U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
210 CCTest(ConditionCode::CC_A, BR(10U, 20U), BR(50U, 60U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
211 CCTest(ConditionCode::CC_GE, BR(10U, 20U), BR(50U, 60U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
212 CCTest(ConditionCode::CC_AE, BR(10U, 20U), BR(50U, 60U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
213 CCTest(ConditionCode::CC_LT, BR(10U, 20U), BR(50U, 60U), BR(10U, 20U), BR(50U, 60U));
214 CCTest(ConditionCode::CC_B, BR(10U, 20U), BR(50U, 60U), BR(10U, 20U), BR(50U, 60U));
215 CCTest(ConditionCode::CC_LE, BR(10U, 20U), BR(50U, 60U), BR(10U, 20U), BR(50U, 60U));
216 CCTest(ConditionCode::CC_BE, BR(10U, 20U), BR(50U, 60U), BR(10U, 20U), BR(50U, 60U));
217 CCTest(ConditionCode::CC_EQ, BR(10U, 20U), BR(50U, 60U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
218 CCTest(ConditionCode::CC_NE, BR(10U, 20U), BR(50U, 60U), BR(10U, 20U), BR(50U, 60U));
219
220 // case 3
221 CCTest(ConditionCode::CC_GT, BR(10U, 60U), BR(20U, 50U), BR(21U, 60U), BR(20U, 50U));
222 CCTest(ConditionCode::CC_A, BR(10U, 60U), BR(20U, 50U), BR(21U, 60U), BR(20U, 50U));
223 CCTest(ConditionCode::CC_GE, BR(10U, 60U), BR(20U, 50U), BR(20U, 60U), BR(20U, 50U));
224 CCTest(ConditionCode::CC_AE, BR(10U, 60U), BR(20U, 50U), BR(20U, 60U), BR(20U, 50U));
225 CCTest(ConditionCode::CC_LT, BR(10U, 60U), BR(20U, 50U), BR(10U, 49U), BR(20U, 50U));
226 CCTest(ConditionCode::CC_B, BR(10U, 60U), BR(20U, 50U), BR(10U, 49U), BR(20U, 50U));
227 CCTest(ConditionCode::CC_LE, BR(10U, 60U), BR(20U, 50U), BR(10U, 50U), BR(20U, 50U));
228 CCTest(ConditionCode::CC_BE, BR(10U, 60U), BR(20U, 50U), BR(10U, 50U), BR(20U, 50U));
229 CCTest(ConditionCode::CC_EQ, BR(10U, 60U), BR(20U, 50U), BR(20U, 50U), BR(20U, 50U));
230 CCTest(ConditionCode::CC_NE, BR(10U, 60U), BR(20U, 50U), BR(10U, 60U), BR(20U, 50U));
231 }
232
TEST_F(BoundsAnalysisTest,BoundsNarrowing2)233 TEST_F(BoundsAnalysisTest, BoundsNarrowing2)
234 {
235 // case 4
236 CCTest(ConditionCode::CC_GT, BR(20U, 60U), BR(10U, 50U), BR(20U, 60U), BR(10U, 50U));
237 CCTest(ConditionCode::CC_A, BR(20U, 60U), BR(10U, 50U), BR(20U, 60U), BR(10U, 50U));
238 CCTest(ConditionCode::CC_GE, BR(20U, 60U), BR(10U, 50U), BR(20U, 60U), BR(10U, 50U));
239 CCTest(ConditionCode::CC_AE, BR(20U, 60U), BR(10U, 50U), BR(20U, 60U), BR(10U, 50U));
240 CCTest(ConditionCode::CC_LT, BR(20U, 60U), BR(10U, 50U), BR(20U, 49U), BR(21U, 50U));
241 CCTest(ConditionCode::CC_B, BR(20U, 60U), BR(10U, 50U), BR(20U, 49U), BR(21U, 50U));
242 CCTest(ConditionCode::CC_LE, BR(20U, 60U), BR(10U, 50U), BR(20U, 50U), BR(20U, 50U));
243 CCTest(ConditionCode::CC_BE, BR(20U, 60U), BR(10U, 50U), BR(20U, 50U), BR(20U, 50U));
244 CCTest(ConditionCode::CC_EQ, BR(20U, 60U), BR(10U, 50U), BR(20U, 50U), BR(20U, 50U));
245 CCTest(ConditionCode::CC_NE, BR(20U, 60U), BR(10U, 50U), BR(20U, 60U), BR(10U, 50U));
246
247 // case 5
248 CCTest(ConditionCode::CC_GT, BR(50U, 60U), BR(10U, 20U), BR(50U, 60U), BR(10U, 20U));
249 CCTest(ConditionCode::CC_A, BR(50U, 60U), BR(10U, 20U), BR(50U, 60U), BR(10U, 20U));
250 CCTest(ConditionCode::CC_GE, BR(50U, 60U), BR(10U, 20U), BR(50U, 60U), BR(10U, 20U));
251 CCTest(ConditionCode::CC_AE, BR(50U, 60U), BR(10U, 20U), BR(50U, 60U), BR(10U, 20U));
252 CCTest(ConditionCode::CC_LT, BR(50U, 60U), BR(10U, 20U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
253 CCTest(ConditionCode::CC_B, BR(50U, 60U), BR(10U, 20U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
254 CCTest(ConditionCode::CC_LE, BR(50U, 60U), BR(10U, 20U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
255 CCTest(ConditionCode::CC_BE, BR(50U, 60U), BR(10U, 20U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
256 CCTest(ConditionCode::CC_EQ, BR(50U, 60U), BR(10U, 20U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
257 CCTest(ConditionCode::CC_NE, BR(50U, 60U), BR(10U, 20U), BR(50U, 60U), BR(10U, 20U));
258
259 // case 6
260 CCTest(ConditionCode::CC_GT, BR(20U, 50U), BR(10U, 60U), BR(20U, 50U), BR(10U, 49U));
261 CCTest(ConditionCode::CC_A, BR(20U, 50U), BR(10U, 60U), BR(20U, 50U), BR(10U, 49U));
262 CCTest(ConditionCode::CC_GE, BR(20U, 50U), BR(10U, 60U), BR(20U, 50U), BR(10U, 50U));
263 CCTest(ConditionCode::CC_AE, BR(20U, 50U), BR(10U, 60U), BR(20U, 50U), BR(10U, 50U));
264 CCTest(ConditionCode::CC_LT, BR(20U, 50U), BR(10U, 60U), BR(20U, 50U), BR(21U, 60U));
265 CCTest(ConditionCode::CC_B, BR(20U, 50U), BR(10U, 60U), BR(20U, 50U), BR(21U, 60U));
266 CCTest(ConditionCode::CC_LE, BR(20U, 50U), BR(10U, 60U), BR(20U, 50U), BR(20U, 60U));
267 CCTest(ConditionCode::CC_BE, BR(20U, 50U), BR(10U, 60U), BR(20U, 50U), BR(20U, 60U));
268 CCTest(ConditionCode::CC_EQ, BR(20U, 50U), BR(10U, 60U), BR(20U, 50U), BR(20U, 50U));
269 CCTest(ConditionCode::CC_NE, BR(20U, 50U), BR(10U, 60U), BR(20U, 50U), BR(10U, 60U));
270 }
271
TEST_F(BoundsAnalysisTest,IntervalCollisions)272 TEST_F(BoundsAnalysisTest, IntervalCollisions)
273 {
274 // Bounds collision
275 CCTest(ConditionCode::CC_GT, BR(-10L, -5L), BR(-5L, 0U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
276 CCTest(ConditionCode::CC_LT, BR(-5L, 0U), BR(-10L, -5L), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
277 // Single value interval collision
278 CCTest(ConditionCode::CC_GT, BR(0U, 20U), BR(20U, 20U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
279 CCTest(ConditionCode::CC_LT, BR(0U, 20U), BR(0U, 0U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
280 CCTest(ConditionCode::CC_GT, BR(16U, 16U), BR(16U, 32U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
281 CCTest(ConditionCode::CC_LT, BR(32U, 32U), BR(16U, 32U), BR(INT64_MIN, INT64_MAX), BR(INT64_MIN, INT64_MAX));
282 }
283
TEST_F(BoundsAnalysisTest,UnionTest)284 TEST_F(BoundsAnalysisTest, UnionTest)
285 {
286 ArenaVector<BoundsRange> ranges(GetGraph()->GetAllocator()->Adapter());
287 ranges.emplace_back(BoundsRange(-10L, 100U));
288 ranges.emplace_back(BoundsRange(-20L, 15U));
289 auto range = BoundsRange::Union(ranges);
290 ASSERT_EQ(range.GetLeft(), -20L);
291 ASSERT_EQ(range.GetRight(), 100U);
292 ranges.clear();
293
294 ranges.emplace_back(BoundsRange(INT64_MIN, -10L));
295 ranges.emplace_back(BoundsRange(10U, INT64_MAX));
296 range = BoundsRange::Union(ranges);
297 ASSERT_EQ(range.GetLeft(), INT64_MIN);
298 ASSERT_EQ(range.GetRight(), INT64_MAX);
299 }
300
TypeFittingBuildGraph()301 void BoundsAnalysisTest::TypeFittingBuildGraph()
302 {
303 GRAPH(GetGraph())
304 {
305 PARAMETER(0U, 0U).u16();
306 PARAMETER(1U, 1U).s64();
307 PARAMETER(2U, 2U).u32();
308 CONSTANT(3U, 0x23U).s64();
309 CONSTANT(4U, 0x30U).s64();
310 BASIC_BLOCK(2U, 3U, 4U)
311 {
312 // v0 -- ANYTHING
313 // v1 -- ANYTHING
314 // v2 -- ANYTHING
315 INST(5U, Opcode::Compare).b().CC(CC_GT).Inputs(1U, 3U);
316 INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
317 }
318 BASIC_BLOCK(4U, 3U, 5U)
319 {
320 // v0 -- ANYTHING
321 // v1 <= 0x23
322 // v2 -- ANYTHING
323 INST(8U, Opcode::Compare).b().CC(CC_GT).Inputs(2U, 4U);
324 INST(9U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(8U);
325 }
326 BASIC_BLOCK(5U, -1L)
327 {
328 // v0 -- ANYTHING
329 // v1 <= 0x23
330 // v2 <= 0x30
331 INST(11U, Opcode::Return).u16().Inputs(0U);
332 }
333 BASIC_BLOCK(3U, -1L)
334 {
335 // v0 -- ANYTHING
336 // v1 -- ANYTHING
337 // v2 -- ANYTHING
338 INST(14U, Opcode::ReturnI).u16().Imm(0x23U);
339 }
340 }
341 }
342
TEST_F(BoundsAnalysisTest,TypeFitting)343 TEST_F(BoundsAnalysisTest, TypeFitting)
344 {
345 TypeFittingBuildGraph();
346 auto rinfo = GetGraph()->GetBoundsRangeInfo();
347 BoundsRange range;
348
349 // BB2
350 range = rinfo->FindBoundsRange(&BB(2U), &INS(0U));
351 EXPECT_EQ(range.GetLeft(), 0U);
352 EXPECT_EQ(range.GetRight(), UINT16_MAX);
353
354 range = rinfo->FindBoundsRange(&BB(2U), &INS(1U));
355 EXPECT_EQ(range.GetLeft(), INT64_MIN);
356 EXPECT_EQ(range.GetRight(), INT64_MAX);
357
358 range = rinfo->FindBoundsRange(&BB(2U), &INS(2U));
359 EXPECT_EQ(range.GetLeft(), 0U);
360 EXPECT_EQ(range.GetRight(), UINT32_MAX);
361
362 // BB4
363 range = rinfo->FindBoundsRange(&BB(2U), &INS(0U));
364 EXPECT_EQ(range.GetLeft(), 0U);
365 EXPECT_EQ(range.GetRight(), UINT16_MAX);
366
367 range = rinfo->FindBoundsRange(&BB(4U), &INS(1U));
368 EXPECT_EQ(range.GetLeft(), INT64_MIN);
369 EXPECT_EQ(range.GetRight(), 0x23U);
370
371 range = rinfo->FindBoundsRange(&BB(2U), &INS(2U));
372 EXPECT_EQ(range.GetLeft(), 0U);
373 EXPECT_EQ(range.GetRight(), UINT32_MAX);
374
375 // BB5
376 range = rinfo->FindBoundsRange(&BB(2U), &INS(0U));
377 EXPECT_EQ(range.GetLeft(), 0U);
378 EXPECT_EQ(range.GetRight(), UINT16_MAX);
379
380 range = rinfo->FindBoundsRange(&BB(4U), &INS(1U));
381 EXPECT_EQ(range.GetLeft(), INT64_MIN);
382 EXPECT_EQ(range.GetRight(), 0x23U);
383
384 range = rinfo->FindBoundsRange(&BB(5U), &INS(2U));
385 EXPECT_EQ(range.GetLeft(), 0U);
386 EXPECT_EQ(range.GetRight(), 0x30U);
387
388 // BB3
389 range = rinfo->FindBoundsRange(&BB(2U), &INS(0U));
390 EXPECT_EQ(range.GetLeft(), 0U);
391 EXPECT_EQ(range.GetRight(), UINT16_MAX);
392
393 range = rinfo->FindBoundsRange(&BB(2U), &INS(1U));
394 EXPECT_EQ(range.GetLeft(), INT64_MIN);
395 EXPECT_EQ(range.GetRight(), INT64_MAX);
396
397 range = rinfo->FindBoundsRange(&BB(2U), &INS(2U));
398 EXPECT_EQ(range.GetLeft(), 0U);
399 EXPECT_EQ(range.GetRight(), UINT32_MAX);
400 }
401
TEST_F(BoundsAnalysisTest,NullCompare)402 TEST_F(BoundsAnalysisTest, NullCompare)
403 {
404 GRAPH(GetGraph())
405 {
406 PARAMETER(0U, 0U).ref();
407 CONSTANT(3U, nullptr);
408 BASIC_BLOCK(2U, 3U, 4U)
409 {
410 INST(4U, Opcode::Compare).b().CC(CC_NE).Inputs(3U, 0U);
411 INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
412 }
413 BASIC_BLOCK(3U, -1L)
414 {
415 INST(7U, Opcode::SaveState).Inputs(0U, 4U).SrcVregs({2U, 3U});
416 INST(8U, Opcode::NullCheck).ref().Inputs(0U, 7U);
417 INST(9U, Opcode::LoadObject).s64().Inputs(8U).TypeId(243U);
418 INST(10U, Opcode::Return).s64().Inputs(9U);
419 }
420 BASIC_BLOCK(4U, -1L)
421 {
422 INST(13U, Opcode::ReturnI).s64().Imm(0x14U);
423 }
424 }
425 auto rinfo = GetGraph()->GetBoundsRangeInfo();
426 EXPECT_EQ(rinfo->FindBoundsRange(&BB(2U), &INS(0U)).GetLeft(), 0U);
427 EXPECT_EQ(rinfo->FindBoundsRange(&BB(2U), &INS(0U)).GetRight(), BoundsRange::GetMax(INS(0U).GetType()));
428
429 EXPECT_NE(rinfo->FindBoundsRange(&BB(3U), &INS(0U)).GetLeft(), 0U);
430 EXPECT_EQ(rinfo->FindBoundsRange(&BB(3U), &INS(0U)).GetRight(), BoundsRange::GetMax(INS(0U).GetType()));
431
432 EXPECT_EQ(rinfo->FindBoundsRange(&BB(4U), &INS(0U)).GetLeft(), 0U);
433 EXPECT_EQ(rinfo->FindBoundsRange(&BB(4U), &INS(0U)).GetRight(), 0U);
434 }
435
TEST_F(BoundsAnalysisTest,InitMoreThenTest)436 TEST_F(BoundsAnalysisTest, InitMoreThenTest)
437 {
438 // For (int i = 10, i < 0, i++) {}
439 // this loop is counable, but init > test value.
440 GRAPH(GetGraph())
441 {
442 CONSTANT(0U, 10U);
443 CONSTANT(1U, 1U);
444 CONSTANT(2U, 0U);
445 BASIC_BLOCK(2U, 3U, 5U)
446 {
447 INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);
448 INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
449 }
450 BASIC_BLOCK(3U, 3U, 5U)
451 {
452 INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
453
454 INST(10U, Opcode::Add).s32().Inputs(4U, 1U);
455 INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);
456 INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
457 }
458 BASIC_BLOCK(5U, 1U)
459 {
460 INST(12U, Opcode::ReturnVoid).v0id();
461 }
462 }
463 auto rinfo = GetGraph()->GetBoundsRangeInfo();
464 auto range = rinfo->FindBoundsRange(&BB(3U), &INS(4U));
465 EXPECT_EQ(range.GetLeft(), INT32_MIN);
466 EXPECT_EQ(range.GetRight(), INT32_MAX);
467 }
468
TEST_F(BoundsAnalysisTest,ModTest)469 TEST_F(BoundsAnalysisTest, ModTest)
470 {
471 auto res = BoundsRange(0U, 10U).Mod(BoundsRange(0U, 2U));
472 EXPECT_EQ(res.GetLeft(), 0U);
473 EXPECT_EQ(res.GetRight(), 1U);
474
475 res = BoundsRange(0U, 10U).Mod(BoundsRange(0U));
476 EXPECT_EQ(res.GetLeft(), INT64_MIN);
477 EXPECT_EQ(res.GetRight(), INT64_MAX);
478
479 // It's correct situation, when right value is 0, and left value isn't 0.
480 res = BoundsRange(-179L, -179L).Mod(BoundsRange(INT64_MIN, 0U));
481 EXPECT_EQ(res.GetLeft(), -179L);
482 EXPECT_EQ(res.GetRight(), 0U);
483
484 res = BoundsRange(5U, 10U).Mod(BoundsRange(-3L));
485 EXPECT_EQ(res.GetLeft(), 0U);
486 EXPECT_EQ(res.GetRight(), 2U);
487
488 res = BoundsRange(-10L, -5L).Mod(BoundsRange(-3L));
489 EXPECT_EQ(res.GetLeft(), -2L);
490 EXPECT_EQ(res.GetRight(), 0U);
491
492 res = BoundsRange(-10L, 10U).Mod(BoundsRange(3U));
493 EXPECT_EQ(res.GetLeft(), -2L);
494 EXPECT_EQ(res.GetRight(), 2U);
495
496 res = BoundsRange(-3L, 3U).Mod(BoundsRange(-10L, 10U));
497 EXPECT_EQ(res.GetLeft(), -3L);
498 EXPECT_EQ(res.GetRight(), 3U);
499 }
500
TEST_F(BoundsAnalysisTest,LoopWithBigStep)501 TEST_F(BoundsAnalysisTest, LoopWithBigStep)
502 {
503 // For (int i = 0, i < 5, i += 10) {}
504 // this loop is countable, and init + step > test value.
505 GRAPH(GetGraph())
506 {
507 CONSTANT(0U, 0U);
508 CONSTANT(1U, 5U);
509 CONSTANT(2U, 10U);
510 BASIC_BLOCK(2U, 3U, 5U)
511 {
512 INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 1U);
513 INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
514 }
515 BASIC_BLOCK(3U, 3U, 5U)
516 {
517 INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
518
519 INST(10U, Opcode::Add).s32().Inputs(4U, 2U);
520 INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 1U);
521 INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
522 }
523 BASIC_BLOCK(5U, 1U)
524 {
525 INST(12U, Opcode::ReturnVoid).v0id();
526 }
527 }
528 auto rinfo = GetGraph()->GetBoundsRangeInfo();
529 auto range = rinfo->FindBoundsRange(&BB(3U), &INS(4U));
530 EXPECT_EQ(range.GetLeft(), 0U);
531 EXPECT_EQ(range.GetRight(), 4U);
532 }
533
TEST_F(BoundsAnalysisTest,LoopWithBigStep2)534 TEST_F(BoundsAnalysisTest, LoopWithBigStep2)
535 {
536 // For (int i = 1, i < 6, i += 2) {}
537 GRAPH(GetGraph())
538 {
539 CONSTANT(0U, 0U);
540 CONSTANT(1U, 6U);
541 CONSTANT(2U, 2U);
542 BASIC_BLOCK(2U, 3U, 5U)
543 {
544 INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 1U);
545 INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
546 }
547 BASIC_BLOCK(3U, 3U, 5U)
548 {
549 INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
550
551 INST(10U, Opcode::Add).s32().Inputs(4U, 2U);
552 INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 1U);
553 INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
554 }
555 BASIC_BLOCK(5U, 1U)
556 {
557 INST(12U, Opcode::ReturnVoid).v0id();
558 }
559 }
560 auto rinfo = GetGraph()->GetBoundsRangeInfo();
561 auto range = rinfo->FindBoundsRange(&BB(3U), &INS(4U));
562 EXPECT_EQ(range.GetLeft(), 0U);
563 // Check that right bound is (upper - 1)
564 EXPECT_EQ(range.GetRight(), 5U);
565 }
566
TEST_F(BoundsAnalysisTest,ShrTest)567 TEST_F(BoundsAnalysisTest, ShrTest)
568 {
569 auto r1 = BoundsRange(2U);
570 auto max = BoundsRange();
571 auto r2 = BoundsRange(4U, 8U);
572 auto neg = BoundsRange(-1L);
573
574 EXPECT_EQ(r2.Shr(r2), max);
575 EXPECT_EQ(r2.Shr(neg), max);
576 EXPECT_EQ(r2.Shr(r1), BoundsRange(1U, 2U));
577
578 EXPECT_EQ(BoundsRange(-1L).Shr(BoundsRange(4U)), BoundsRange(0x0FFFFFFFFFFFFFFFU));
579 EXPECT_EQ(BoundsRange(-1L, 16U).Shr(BoundsRange(4U)), BoundsRange(0U, 0x0FFFFFFFFFFFFFFFU));
580 EXPECT_EQ(BoundsRange(9U, 15U).Shr(BoundsRange(2U)), BoundsRange(2U, 3U));
581 EXPECT_EQ(BoundsRange(-15L, -9L).Shr(BoundsRange(2U)), BoundsRange(0x3FFFFFFFFFFFFFFCU, 0x3FFFFFFFFFFFFFFDU));
582 EXPECT_EQ(BoundsRange(-100L, 100U).Shr(BoundsRange(4U)), BoundsRange(0U, 0x0FFFFFFFFFFFFFFFU));
583 }
584
TEST_F(BoundsAnalysisTest,AShrTest)585 TEST_F(BoundsAnalysisTest, AShrTest)
586 {
587 auto r1 = BoundsRange(2U);
588 auto max = BoundsRange();
589 auto r2 = BoundsRange(4U, 8U);
590 auto neg = BoundsRange(-1L);
591
592 EXPECT_EQ(r2.AShr(r2), max);
593 EXPECT_EQ(r2.AShr(neg), max);
594 EXPECT_EQ(r2.AShr(r1), BoundsRange(1U, 2U));
595
596 EXPECT_EQ(BoundsRange(-1L).AShr(BoundsRange(4U)), BoundsRange(-1L));
597 EXPECT_EQ(BoundsRange(-1L, 16U).AShr(BoundsRange(4U)), BoundsRange(-1L, 1U));
598 }
599
TEST_F(BoundsAnalysisTest,ShlTest)600 TEST_F(BoundsAnalysisTest, ShlTest)
601 {
602 auto max = BoundsRange();
603 auto r = BoundsRange(4U, 8U);
604 auto neg = BoundsRange(-1L);
605
606 EXPECT_EQ(r.Shl(r), max);
607 EXPECT_EQ(r.Shl(neg), max);
608
609 EXPECT_EQ(r.Shl(BoundsRange(2U)), BoundsRange(16U, 32U));
610 EXPECT_EQ(BoundsRange(-1L).Shl(BoundsRange(4U)), BoundsRange(0xFFFFFFFFFFFFFFF0U));
611 EXPECT_EQ(BoundsRange(-1L, 16U).Shl(BoundsRange(4U)), BoundsRange(0xFFFFFFFFFFFFFFF0U, 256U));
612 EXPECT_EQ(BoundsRange(16U, 0x0FFFFFFFFFFFFFFFU).Shl(BoundsRange(4U)), BoundsRange());
613 }
614
TEST_F(BoundsAnalysisTest,SignedDivTest)615 TEST_F(BoundsAnalysisTest, SignedDivTest)
616 {
617 GRAPH(GetGraph())
618 {
619 PARAMETER(0U, 0U).s32();
620 CONSTANT(1U, 4U);
621 BASIC_BLOCK(2U, -1L)
622 {
623 INST(2U, Opcode::Div).s32().Inputs(0U, 1U);
624 INST(3U, Opcode::Return).s32().Inputs(2U);
625 }
626 }
627
628 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
629 ASSERT_FALSE(GetGraph()->RunPass<Cleanup>());
630
631 auto bb = &BB(2U);
632
633 auto graph = CreateEmptyGraph();
634 GRAPH(graph)
635 {
636 PARAMETER(0U, 0U).s32();
637 CONSTANT(1U, 4U);
638 BASIC_BLOCK(2U, -1L)
639 {
640 INST(2U, Opcode::Div).s32().Inputs(0U, 1U);
641 INST(3U, Opcode::Return).s32().Inputs(2U);
642 }
643 }
644 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
645
646 auto bri = GetGraph()->GetBoundsRangeInfo();
647 auto range = bri->FindBoundsRange(bb, bb->GetLastInst()->GetInput(0U).GetInst());
648 ASSERT_EQ(range, BoundsRange(INT32_MIN / 4L, INT32_MAX / 4L));
649 }
650
TEST_F(BoundsAnalysisTest,AndTest)651 TEST_F(BoundsAnalysisTest, AndTest)
652 {
653 EXPECT_EQ(BoundsRange().And(BoundsRange(1U, 2U)), BoundsRange());
654 EXPECT_EQ(BoundsRange().And(BoundsRange(0x2U)), BoundsRange(0U, 0x2U));
655 EXPECT_EQ(BoundsRange().And(BoundsRange(0x3U)), BoundsRange(0U, 0x3U));
656 EXPECT_EQ(BoundsRange().And(BoundsRange(-1L)), BoundsRange());
657 EXPECT_EQ(BoundsRange().And(BoundsRange(0x8000000000000000U)), BoundsRange());
658 }
659
TEST_F(BoundsAnalysisTest,UINT64_INPUTS)660 TEST_F(BoundsAnalysisTest, UINT64_INPUTS)
661 {
662 GRAPH(GetGraph())
663 {
664 PARAMETER(0U, 0U).ref();
665 BASIC_BLOCK(2U, -1L)
666 {
667 INST(1U, Opcode::LoadObject).u64().Inputs(0U);
668 INST(2U, Opcode::LoadObject).u64().Inputs(0U);
669 INST(3U, Opcode::Add).i64().Inputs(1U, 2U);
670 INST(4U, Opcode::Return).u64().Inputs(3U);
671 }
672 }
673 auto bri = GetGraph()->GetBoundsRangeInfo();
674 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(1U)), BoundsRange(0U, INT64_MAX));
675 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(3U)), BoundsRange(INT64_MIN, INT64_MAX));
676 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(4U)), BoundsRange(0U, INT64_MAX));
677 }
678
TEST_F(BoundsAnalysisTest,Different_types)679 TEST_F(BoundsAnalysisTest, Different_types)
680 {
681 GRAPH(GetGraph())
682 {
683 PARAMETER(0U, 0U).u64();
684 CONSTANT(1U, 2U);
685 BASIC_BLOCK(2U, -1L)
686 {
687 INST(2U, Opcode::Div).i64().Inputs(0U, 1U);
688 INST(3U, Opcode::Return).i64().Inputs(2U);
689 }
690 }
691 auto bri = GetGraph()->GetBoundsRangeInfo();
692 ASSERT_EQ(bri->FindBoundsRange(&BB(0U), &INS(0U)), BoundsRange(0U, INT64_MAX));
693 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(2U)), BoundsRange(INT64_MIN, INT64_MAX));
694 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(3U)), BoundsRange(INT64_MIN, INT64_MAX));
695 }
696
697 /*
698 * [0]
699 * |
700 * v
701 * /------>[2]------\
702 * | | |
703 * | [3] |
704 * | / \ |
705 * | v v v
706 * | [4] [5] [7]
707 * | \ / |
708 * \-------[6] [exit]
709 *
710 */
TEST_F(BoundsAnalysisTest,LoopWithBranch)711 TEST_F(BoundsAnalysisTest, LoopWithBranch)
712 {
713 GRAPH(GetGraph())
714 {
715 PARAMETER(0U, 0U).b();
716 CONSTANT(1U, 0U);
717 CONSTANT(15U, 1U);
718 CONSTANT(2U, 2U);
719 CONSTANT(25U, 10U);
720 BASIC_BLOCK(2U, 3U, 7U)
721 {
722 INST(3U, Opcode::Phi).Inputs(1U, 9U).u64(); // index
723 INST(35U, Opcode::Phi).Inputs(1U, 8U).u64(); // init
724 INST(4U, Opcode::Compare).CC(CC_LT).b().Inputs(3U, 25U);
725 INST(45U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
726 }
727 BASIC_BLOCK(3U, 4U, 5U)
728 {
729 INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(0U);
730 }
731 BASIC_BLOCK(4U, 6U)
732 {
733 INST(6U, Opcode::Add).Inputs(35U, 2U).u64();
734 }
735 BASIC_BLOCK(5U, 6U)
736 {
737 INST(7U, Opcode::Add).Inputs(35U, 15U).u64();
738 }
739 BASIC_BLOCK(6U, 2U)
740 {
741 INST(8U, Opcode::Phi).Inputs(6U, 7U).u64(); // update
742 INST(9U, Opcode::Add).Inputs(3U, 15U).u64();
743 }
744 BASIC_BLOCK(7U, -1L)
745 {
746 INST(10U, Opcode::Return).Inputs(35U).u64();
747 }
748 }
749 auto bri = GetGraph()->GetBoundsRangeInfo();
750 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(3U)), BoundsRange(0U, 9U));
751 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(35U)), BoundsRange(0U, 20U));
752 ASSERT_EQ(bri->FindBoundsRange(&BB(6U), &INS(8U)), BoundsRange(10U, 20U));
753 }
754
TEST_F(BoundsAnalysisTest,NegativePhi)755 TEST_F(BoundsAnalysisTest, NegativePhi)
756 {
757 GRAPH(GetGraph())
758 {
759 CONSTANT(2U, 100U);
760 CONSTANT(3U, 5U);
761 CONSTANT(4U, 0U);
762 CONSTANT(5U, 4U);
763 CONSTANT(16U, 1U);
764 BASIC_BLOCK(3U, 4U, 2U)
765 {
766 INST(21U, Opcode::Compare).CC(CC_GE).b().Inputs(4U, 3U).SrcType(DataType::INT32);
767 INST(22U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(21U);
768 }
769 BASIC_BLOCK(2U, 4U, 2U)
770 {
771 INST(9U, Opcode::Phi).Inputs(4U, 15U).i32();
772 INST(10U, Opcode::Phi).Inputs(5U, 14U).i32();
773 INST(14U, Opcode::Sub).Inputs(2U, 10U).i32();
774 INST(15U, Opcode::Add).Inputs(9U, 16U).i32();
775 INST(12U, Opcode::Compare).CC(CC_GE).b().Inputs(15U, 3U);
776 INST(13U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(12U);
777 }
778 BASIC_BLOCK(4U, -1L)
779 {
780 INST(20U, Opcode::Return).Inputs(16U).i32();
781 }
782 }
783 auto bri = GetGraph()->GetBoundsRangeInfo();
784 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(9U)), BoundsRange(0U, 4U));
785 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(10U)), BoundsRange(INT32_MIN, INT32_MAX));
786 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(14U)), BoundsRange(INT32_MIN, INT32_MAX));
787 ASSERT_EQ(bri->FindBoundsRange(&BB(2U), &INS(15U)), BoundsRange(1U, 5U));
788 }
789 // NOLINTEND(readability-magic-numbers)
790
791 } // namespace ark::compiler
792