Flutter Engine
The Flutter Engine
range_analysis_test.cc
Go to the documentation of this file.
1// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
7#include "vm/unit_test.h"
8
9namespace dart {
10
11TEST_CASE(RangeTests) {
12 Range* zero =
14 Range* positive = new Range(RangeBoundary::FromConstant(0),
16 Range* negative = new Range(RangeBoundary::FromConstant(-1),
18 Range* range_x = new Range(RangeBoundary::FromConstant(-15),
20 EXPECT(positive->IsPositive());
21 EXPECT(zero->Overlaps(0, 0));
22 EXPECT(positive->Overlaps(0, 0));
23 EXPECT(!negative->Overlaps(0, 0));
24 EXPECT(range_x->Overlaps(0, 0));
25 EXPECT(range_x->IsWithin(-15, 100));
26 EXPECT(!range_x->IsWithin(-15, 99));
27 EXPECT(!range_x->IsWithin(-14, 100));
28
29#define TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, Clamp, res_min, \
30 res_max) \
31 { \
32 RangeBoundary min, max; \
33 Range* left_range = new Range(RangeBoundary::FromConstant(l_min), \
34 RangeBoundary::FromConstant(l_max)); \
35 Range* shift_range = new Range(RangeBoundary::FromConstant(r_min), \
36 RangeBoundary::FromConstant(r_max)); \
37 Op(left_range, shift_range, &min, &max); \
38 min = Clamp(min); \
39 max = Clamp(max); \
40 EXPECT(min.Equals(res_min)); \
41 if (FLAG_support_il_printer && !min.Equals(res_min)) { \
42 OS::PrintErr("%s\n", min.ToCString()); \
43 } \
44 EXPECT(max.Equals(res_max)); \
45 if (FLAG_support_il_printer && !max.Equals(res_max)) { \
46 OS::PrintErr("%s\n", max.ToCString()); \
47 } \
48 }
49
50#define NO_CLAMP(b) (b)
51#define TEST_RANGE_OP(Op, l_min, l_max, r_min, r_max, result_min, result_max) \
52 TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, NO_CLAMP, result_min, \
53 result_max)
54
55#define CLAMP_TO_SMI(b) (b.Clamp(RangeBoundary::kRangeBoundarySmi))
56#define TEST_RANGE_OP_SMI(Op, l_min, l_max, r_min, r_max, res_min, res_max) \
57 TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, CLAMP_TO_SMI, res_min, res_max)
58
59 TEST_RANGE_OP(Range::Shl, -15, 100, 0, 2, RangeBoundary(-60),
60 RangeBoundary(400));
61 TEST_RANGE_OP(Range::Shl, -15, 100, -2, 2, RangeBoundary(-60),
62 RangeBoundary(400));
63 TEST_RANGE_OP(Range::Shl, -15, -10, 1, 2, RangeBoundary(-60),
64 RangeBoundary(-20));
71 TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62,
74 TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30, RangeBoundary(-(1 << 30)),
75 RangeBoundary(1 << 30));
76 } else {
78 TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30,
81 TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62,
84 }
89
92 RangeBoundary(4));
93 TEST_RANGE_OP(Range::Shr, -16, -8, 1, 2, RangeBoundary(-8),
94 RangeBoundary(-2));
100#undef TEST_RANGE_OP
101}
102
103TEST_CASE(RangeTestsInt64Range) {
105
107 EXPECT(all->Equals(&fullInt64Range));
108 EXPECT(all->Overlaps(0, 0));
109 EXPECT(all->Overlaps(-1, 1));
110 EXPECT(!all->IsWithin(0, 100));
111
112 Range* positive =
114 EXPECT(positive->Overlaps(0, 1));
115 EXPECT(positive->Overlaps(1, 100));
116 EXPECT(positive->Overlaps(-1, 0));
117
118 Range* negative =
120 EXPECT(negative->Overlaps(-1, 0));
121 EXPECT(negative->Overlaps(-2, -1));
122
123 Range* negpos =
125 EXPECT(!negpos->IsPositive());
126
127 Range* c =
129
131}
132
134 // Use kMin/kMax instead of +/-inf as any range with a +/-inf bound is
135 // converted to the full int64 range due to wrap-around.
136 const RangeBoundary negativeInfinity =
138 const RangeBoundary positiveInfinity =
140
141 // [-inf, +inf].
142 const Range& range_0 = *(new Range(negativeInfinity, positiveInfinity));
143 // [-inf, -1].
144 const Range& range_a =
145 *(new Range(negativeInfinity, RangeBoundary::FromConstant(-1)));
146 // [-inf, 0].
147 const Range& range_b =
148 *(new Range(negativeInfinity, RangeBoundary::FromConstant(0)));
149 // [-inf, 1].
150 const Range& range_c =
151 *(new Range(negativeInfinity, RangeBoundary::FromConstant(1)));
152 // [-1, +inf]
153 const Range& range_d =
154 *(new Range(RangeBoundary::FromConstant(-1), positiveInfinity));
155 // [0, +inf]
156 const Range& range_e =
157 *(new Range(RangeBoundary::FromConstant(0), positiveInfinity));
158 // [1, +inf].
159 const Range& range_f =
160 *(new Range(RangeBoundary::FromConstant(1), positiveInfinity));
161 // [1, 2].
162 const Range& range_g = *(new Range(RangeBoundary::FromConstant(1),
164 // [-1, -2].
165 const Range& range_h = *(new Range(RangeBoundary::FromConstant(-1),
167 // [-1, 1].
168 const Range& range_i = *(new Range(RangeBoundary::FromConstant(-1),
170
171 // OnlyPositiveOrZero.
172 EXPECT(!Range::OnlyPositiveOrZero(range_a, range_b));
173 EXPECT(!Range::OnlyPositiveOrZero(range_b, range_c));
174 EXPECT(!Range::OnlyPositiveOrZero(range_c, range_d));
175 EXPECT(!Range::OnlyPositiveOrZero(range_d, range_e));
176 EXPECT(Range::OnlyPositiveOrZero(range_e, range_f));
177 EXPECT(!Range::OnlyPositiveOrZero(range_d, range_d));
178 EXPECT(Range::OnlyPositiveOrZero(range_e, range_e));
179 EXPECT(Range::OnlyPositiveOrZero(range_f, range_g));
180 EXPECT(!Range::OnlyPositiveOrZero(range_g, range_h));
181 EXPECT(!Range::OnlyPositiveOrZero(range_i, range_i));
182
183 // OnlyNegativeOrZero.
184 EXPECT(Range::OnlyNegativeOrZero(range_a, range_b));
185 EXPECT(!Range::OnlyNegativeOrZero(range_b, range_c));
186 EXPECT(Range::OnlyNegativeOrZero(range_b, range_b));
187 EXPECT(!Range::OnlyNegativeOrZero(range_c, range_c));
188 EXPECT(!Range::OnlyNegativeOrZero(range_c, range_d));
189 EXPECT(!Range::OnlyNegativeOrZero(range_d, range_e));
190 EXPECT(!Range::OnlyNegativeOrZero(range_e, range_f));
191 EXPECT(!Range::OnlyNegativeOrZero(range_f, range_g));
192 EXPECT(!Range::OnlyNegativeOrZero(range_g, range_h));
193 EXPECT(Range::OnlyNegativeOrZero(range_h, range_h));
194 EXPECT(!Range::OnlyNegativeOrZero(range_i, range_i));
195
196 // [-inf, +inf].
197 EXPECT(!Range::OnlyNegativeOrZero(range_0, range_0));
198 EXPECT(!Range::OnlyPositiveOrZero(range_0, range_0));
199
201 EXPECT(Range::ConstantAbsMax(&range_h) == 2);
202 EXPECT(Range::ConstantAbsMax(&range_i) == 1);
203
204 // RangeBoundary.Equals.
206 EXPECT(
208}
209
210TEST_CASE(RangeBinaryOp) {
211 Range* range_a = new Range(RangeBoundary::FromConstant(-1),
214 EXPECT(range_a->min().ConstantValue() == -1);
215 EXPECT(range_a->max().ConstantValue() == kMaxInt32);
217
221 EXPECT(range_b->min().ConstantValue() == kMinInt32);
222 EXPECT(range_b->max().ConstantValue() == 1);
224
225 {
227 Range::BinaryOp(Token::kADD, range_a, range_b, nullptr, &result);
229 EXPECT(result.min().Equals(
231 EXPECT(result.max().Equals(
233 }
234
235 // Test that [5, 10] + [0, 5] = [5, 15].
236 Range* range_c = new Range(RangeBoundary::FromConstant(5),
238 Range* range_d =
240
241 {
243 Range::BinaryOp(Token::kADD, range_c, range_d, nullptr, &result);
245 EXPECT(result.min().ConstantValue() == 5);
246 EXPECT(result.max().ConstantValue() == 15);
247 }
248
249 // Test that [0xff, 0xfff] & [0xf, 0xf] = [0x0, 0xf].
250 Range* range_e = new Range(RangeBoundary::FromConstant(0xff),
252 Range* range_f = new Range(RangeBoundary::FromConstant(0xf),
254 {
256 Range::BinaryOp(Token::kBIT_AND, range_e, range_f, nullptr, &result);
258 EXPECT(result.min().ConstantValue() == 0x0);
259 EXPECT(result.max().ConstantValue() == 0xf);
260 }
261}
262
263TEST_CASE(RangeAdd) {
264#define TEST_RANGE_ADD(l_min, l_max, r_min, r_max, result_min, result_max) \
265 { \
266 RangeBoundary min, max; \
267 Range* left_range = new Range(RangeBoundary::FromConstant(l_min), \
268 RangeBoundary::FromConstant(l_max)); \
269 Range* right_range = new Range(RangeBoundary::FromConstant(r_min), \
270 RangeBoundary::FromConstant(r_max)); \
271 EXPECT(left_range->min().ConstantValue() == l_min); \
272 EXPECT(left_range->max().ConstantValue() == l_max); \
273 EXPECT(right_range->min().ConstantValue() == r_min); \
274 EXPECT(right_range->max().ConstantValue() == r_max); \
275 Range::Add(left_range, right_range, &min, &max, nullptr); \
276 EXPECT(min.Equals(result_min)); \
277 if (FLAG_support_il_printer && !min.Equals(result_min)) { \
278 OS::PrintErr("%s != %s\n", min.ToCString(), result_min.ToCString()); \
279 } \
280 EXPECT(max.Equals(result_max)); \
281 if (FLAG_support_il_printer && !max.Equals(result_max)) { \
282 OS::PrintErr("%s != %s\n", max.ToCString(), result_max.ToCString()); \
283 } \
284 }
285
286 // [kMaxInt32, kMaxInt32 + 15] + [10, 20] = [kMaxInt32 + 10, kMaxInt32 + 35].
287 TEST_RANGE_ADD(static_cast<int64_t>(kMaxInt32),
288 static_cast<int64_t>(kMaxInt32) + 15, static_cast<int64_t>(10),
289 static_cast<int64_t>(20),
290 RangeBoundary(static_cast<int64_t>(kMaxInt32) + 10),
291 RangeBoundary(static_cast<int64_t>(kMaxInt32) + 35));
292
293 // [kMaxInt32 - 15, kMaxInt32 + 15] + [15, -15] = [kMaxInt32, kMaxInt32].
294 TEST_RANGE_ADD(static_cast<int64_t>(kMaxInt32) - 15,
295 static_cast<int64_t>(kMaxInt32) + 15, static_cast<int64_t>(15),
296 static_cast<int64_t>(-15),
297 RangeBoundary(static_cast<int64_t>(kMaxInt32)),
298 RangeBoundary(static_cast<int64_t>(kMaxInt32)));
299
300 // [kMaxInt32, kMaxInt32 + 15] + [10, kMaxInt64] = [kMinInt64, kMaxInt64].
301 TEST_RANGE_ADD(static_cast<int64_t>(kMaxInt32),
302 static_cast<int64_t>(kMaxInt32) + 15, static_cast<int64_t>(10),
303 static_cast<int64_t>(kMaxInt64), RangeBoundary(kMinInt64),
305
306 // [kMinInt64, kMaxInt32 + 15] + [10, 20] = [kMinInt64 + 10, kMaxInt32 + 35].
307 TEST_RANGE_ADD(static_cast<int64_t>(kMinInt64),
308 static_cast<int64_t>(kMaxInt32) + 15, static_cast<int64_t>(10),
309 static_cast<int64_t>(20),
310 RangeBoundary(static_cast<int64_t>(kMinInt64) + 10),
311 RangeBoundary(static_cast<int64_t>(kMaxInt32) + 35));
312
313 // [0, 0] + [kMinInt64, kMaxInt64] = [kMinInt64, kMaxInt64].
314 TEST_RANGE_ADD(static_cast<int64_t>(0), static_cast<int64_t>(0),
315 static_cast<int64_t>(kMinInt64),
316 static_cast<int64_t>(kMaxInt64), RangeBoundary(kMinInt64),
318
319 // Overflows.
320
321 // [-1, 1] + [kMinInt64, kMaxInt64] = [kMinInt64, kMaxInt64].
322 TEST_RANGE_ADD(static_cast<int64_t>(-1), static_cast<int64_t>(1),
323 static_cast<int64_t>(kMinInt64),
324 static_cast<int64_t>(kMaxInt64), RangeBoundary(kMinInt64),
326
327 // [kMaxInt64, kMaxInt64] + [kMaxInt64, kMaxInt64] = [kMinInt64, kMaxInt64].
329 static_cast<int64_t>(kMaxInt64), static_cast<int64_t>(kMaxInt64),
330 static_cast<int64_t>(kMaxInt64), static_cast<int64_t>(kMaxInt64),
332
333 // [kMaxInt64, kMaxInt64] + [1, 1] = [kMinInt64, kMaxInt64].
334 TEST_RANGE_ADD(static_cast<int64_t>(kMaxInt64),
335 static_cast<int64_t>(kMaxInt64), static_cast<int64_t>(1),
336 static_cast<int64_t>(1), RangeBoundary(kMinInt64),
338
339#undef TEST_RANGE_ADD
340}
341
342TEST_CASE(RangeSub) {
343#define TEST_RANGE_SUB(l_min, l_max, r_min, r_max, result_min, result_max) \
344 { \
345 RangeBoundary min, max; \
346 Range* left_range = new Range(RangeBoundary::FromConstant(l_min), \
347 RangeBoundary::FromConstant(l_max)); \
348 Range* right_range = new Range(RangeBoundary::FromConstant(r_min), \
349 RangeBoundary::FromConstant(r_max)); \
350 EXPECT(left_range->min().ConstantValue() == l_min); \
351 EXPECT(left_range->max().ConstantValue() == l_max); \
352 EXPECT(right_range->min().ConstantValue() == r_min); \
353 EXPECT(right_range->max().ConstantValue() == r_max); \
354 Range::Sub(left_range, right_range, &min, &max, nullptr); \
355 EXPECT(min.Equals(result_min)); \
356 if (FLAG_support_il_printer && !min.Equals(result_min)) { \
357 OS::PrintErr("%s != %s\n", min.ToCString(), result_min.ToCString()); \
358 } \
359 EXPECT(max.Equals(result_max)); \
360 if (FLAG_support_il_printer && !max.Equals(result_max)) { \
361 OS::PrintErr("%s != %s\n", max.ToCString(), result_max.ToCString()); \
362 } \
363 }
364
365 // [kMaxInt32, kMaxInt32 + 15] - [10, 20] = [kMaxInt32 - 20, kMaxInt32 + 5].
366 TEST_RANGE_SUB(static_cast<int64_t>(kMaxInt32),
367 static_cast<int64_t>(kMaxInt32) + 15, static_cast<int64_t>(10),
368 static_cast<int64_t>(20),
369 RangeBoundary(static_cast<int64_t>(kMaxInt32) - 20),
370 RangeBoundary(static_cast<int64_t>(kMaxInt32) + 5));
371
372 // [kMintInt64, kMintInt64] - [1, 1] = [kMinInt64, kMaxInt64].
373 TEST_RANGE_SUB(static_cast<int64_t>(kMinInt64),
374 static_cast<int64_t>(kMinInt64), static_cast<int64_t>(1),
375 static_cast<int64_t>(1), RangeBoundary(kMinInt64),
377
378 // [1, 1] - [kMintInt64, kMintInt64] = [kMinInt64, kMaxInt64].
379 TEST_RANGE_SUB(static_cast<int64_t>(1), static_cast<int64_t>(1),
380 static_cast<int64_t>(kMinInt64),
381 static_cast<int64_t>(kMinInt64), RangeBoundary(kMinInt64),
383
384 // [kMaxInt32 + 10, kMaxInt32 + 20] - [-20, -20] =
385 // [kMaxInt32 + 30, kMaxInt32 + 40].
386 TEST_RANGE_SUB(static_cast<int64_t>(kMaxInt32) + 10,
387 static_cast<int64_t>(kMaxInt32) + 20,
388 static_cast<int64_t>(-20), static_cast<int64_t>(-20),
389 RangeBoundary(static_cast<int64_t>(kMaxInt32) + 30),
390 RangeBoundary(static_cast<int64_t>(kMaxInt32) + 40));
391
392#undef TEST_RANGE_SUB
393}
394
395TEST_CASE(RangeAnd) {
396#define TEST_RANGE_AND(l_min, l_max, r_min, r_max, result_min, result_max) \
397 { \
398 RangeBoundary min, max; \
399 Range* left_range = new Range(RangeBoundary::FromConstant(l_min), \
400 RangeBoundary::FromConstant(l_max)); \
401 Range* right_range = new Range(RangeBoundary::FromConstant(r_min), \
402 RangeBoundary::FromConstant(r_max)); \
403 EXPECT(left_range->min().ConstantValue() == l_min); \
404 EXPECT(left_range->max().ConstantValue() == l_max); \
405 EXPECT(right_range->min().ConstantValue() == r_min); \
406 EXPECT(right_range->max().ConstantValue() == r_max); \
407 Range::And(left_range, right_range, &min, &max); \
408 EXPECT(min.Equals(result_min)); \
409 if (FLAG_support_il_printer && !min.Equals(result_min)) { \
410 OS::PrintErr("%s != %s\n", min.ToCString(), result_min.ToCString()); \
411 } \
412 EXPECT(max.Equals(result_max)); \
413 if (FLAG_support_il_printer && !max.Equals(result_max)) { \
414 OS::PrintErr("%s != %s\n", max.ToCString(), result_max.ToCString()); \
415 } \
416 }
417
418 // [0xff, 0xfff] & [0xf, 0xf] = [0x0, 0xf].
419 TEST_RANGE_AND(static_cast<int64_t>(0xff), static_cast<int64_t>(0xfff),
420 static_cast<int64_t>(0xf), static_cast<int64_t>(0xf),
422
423 // [0xffffffff, 0xffffffff] & [0xfffffffff, 0xfffffffff] = [0x0, 0xfffffffff].
425 static_cast<int64_t>(0xffffffff), static_cast<int64_t>(0xffffffff),
426 static_cast<int64_t>(0xfffffffff), static_cast<int64_t>(0xfffffffff),
428 RangeBoundary(static_cast<int64_t>(0xfffffffff)));
429
430 // [0xffffffff, 0xffffffff] & [-20, 20] = [0x0, 0xffffffff].
431 TEST_RANGE_AND(static_cast<int64_t>(0xffffffff),
432 static_cast<int64_t>(0xffffffff), static_cast<int64_t>(-20),
433 static_cast<int64_t>(20), RangeBoundary::FromConstant(0),
434 RangeBoundary(static_cast<int64_t>(0xffffffff)));
435
436 // [-20, 20] & [0xffffffff, 0xffffffff] = [0x0, 0xffffffff].
437 TEST_RANGE_AND(static_cast<int64_t>(-20), static_cast<int64_t>(20),
438 static_cast<int64_t>(0xffffffff),
439 static_cast<int64_t>(0xffffffff),
441 RangeBoundary(static_cast<int64_t>(0xffffffff)));
442
443 // Test that [-20, 20] & [-20, 20] = [-32, 31].
444 TEST_RANGE_AND(static_cast<int64_t>(-20), static_cast<int64_t>(20),
445 static_cast<int64_t>(-20), static_cast<int64_t>(20),
446 RangeBoundary(-32), RangeBoundary(31));
447
448#undef TEST_RANGE_AND
449}
450
451TEST_CASE(RangeIntersectionMinMax) {
452 // Test IntersectionMin and IntersectionMax methods which for constants are
453 // simply defined as Max/Min respectively.
454
455 // Constants.
456 // MIN(0, 1) == 0
459 .ConstantValue() == 0);
460 // MIN(0, -1) == -1
463 .ConstantValue() == -1);
464
465 // MIN(1, 0) == 0
468 .ConstantValue() == 0);
469 // MIN(-1, 0) == -1
472 .ConstantValue() == -1);
473
474 // MAX(0, 1) == 1
477 .ConstantValue() == 1);
478
479 // MAX(0, -1) == 0
482 .ConstantValue() == 0);
483
484 // MAX(1, 0) == 1
487 .ConstantValue() == 1);
488 // MAX(-1, 0) == 0
491 .ConstantValue() == 0);
492
493 // Constants vs. kMinInt64 / kMaxInt64.
496 .ConstantValue() == -1);
497
500 .ConstantValue() == -1);
501
504 .ConstantValue() == 1);
505
508 .ConstantValue() == 1);
509
512 .ConstantValue() == -1);
513
516 .ConstantValue() == -1);
517
520 .ConstantValue() == 1);
521
524 .ConstantValue() == 1);
525}
526
527TEST_CASE(RangeJoinMinMax) {
528 // Test IntersectionMin and IntersectionMax methods which for constants are
529 // simply defined as Min/Max respectively.
531
532 // Constants.
535 .ConstantValue() == 1);
538 .ConstantValue() == 0);
541 .ConstantValue() == 1);
544 .ConstantValue() == 0);
547 .ConstantValue() == 0);
550 .ConstantValue() == -1);
553 .ConstantValue() == 0);
556 .ConstantValue() == -1);
557
558 // Constants vs. kMinInt64 / kMaxInt64.
561 .IsMinimumOrBelow(size));
562
565 .IsMinimumOrBelow(size));
566
569 .IsMinimumOrBelow(size));
570
573 .IsMinimumOrBelow(size));
574
577 .IsMaximumOrAbove(size));
578
581 .IsMaximumOrAbove(size));
582
585 .IsMaximumOrAbove(size));
586
589 .IsMaximumOrAbove(size));
590}
591
592#if defined(DART_PRECOMPILER) && defined(TARGET_ARCH_IS_64_BIT)
593
594// Regression test for https://github.com/dart-lang/sdk/issues/48153.
595ISOLATE_UNIT_TEST_CASE(RangeAnalysis_ShiftUint32Op) {
596 const char* kScript = R"(
597 @pragma('vm:never-inline')
598 int foo(int hash) {
599 return 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
600 }
601 void main() {
602 foo(42);
603 }
604 )";
605
606 const auto& root_library = Library::Handle(LoadTestScript(kScript));
607
608 Invoke(root_library, "main");
609
610 const auto& function = Function::Handle(GetFunction(root_library, "foo"));
611 TestPipeline pipeline(function, CompilerPass::kAOT);
612 FlowGraph* flow_graph = pipeline.RunPasses({});
613
614 auto entry = flow_graph->graph_entry()->normal_entry();
615 EXPECT(entry != nullptr);
616 ILMatcher cursor(flow_graph, entry, /*trace=*/true,
618
619 ShiftUint32OpInstr* shift = nullptr;
620
621 RELEASE_ASSERT(cursor.TryMatch({
622 kMoveGlob,
623 kMatchAndMoveBinaryUint32Op,
624 kMoveGlob,
625 {kMatchAndMoveShiftUint32Op, &shift},
626 kMoveGlob,
627 kMatchAndMoveBinaryUint32Op,
628 kMoveGlob,
629 kMatchAndMoveBinaryUint32Op,
630 kMoveGlob,
631 kMatchDartReturn,
632 }));
633
634 EXPECT(shift->shift_range() != nullptr);
635 EXPECT(shift->shift_range()->min().ConstantValue() == 10);
636 EXPECT(shift->shift_range()->max().ConstantValue() == 10);
637}
638
639#endif // defined(DART_PRECOMPILER) && defined(TARGET_ARCH_IS_64_BIT)
640
641ISOLATE_UNIT_TEST_CASE(RangeAnalysis_LoadClassId) {
642 const char* kScript = R"(
643 @pragma('vm:never-inline')
644 bool foo(num x) {
645 return x is int;
646 }
647 void main() {
648 foo(42);
649 }
650 )";
651
652 const auto& root_library = Library::Handle(LoadTestScript(kScript));
653 Invoke(root_library, "main");
654
655 const auto& function = Function::Handle(GetFunction(root_library, "foo"));
656 TestPipeline pipeline(function, CompilerPass::kAOT);
657 FlowGraph* flow_graph = pipeline.RunPasses({});
658
659 auto entry = flow_graph->graph_entry()->normal_entry();
660 EXPECT(entry != nullptr);
661 ILMatcher cursor(flow_graph, entry, /*trace=*/true,
662 ParallelMovesHandling::kSkip);
663
664 LoadClassIdInstr* load_cid = nullptr;
665
666 RELEASE_ASSERT(cursor.TryMatch({
667 kMoveGlob,
668 {kMatchAndMoveLoadClassId, &load_cid},
669 kMoveGlob,
670 kMatchAndMoveTestRange,
671 kMoveGlob,
672 kMatchDartReturn,
673 }));
674
675 EXPECT(load_cid->range() != nullptr);
676 EXPECT(kSmiCid < kMintCid);
677 EXPECT(kMintCid < kDoubleCid);
678 EXPECT(load_cid->range()->min().ConstantValue() == kSmiCid);
679 EXPECT(load_cid->range()->max().ConstantValue() == kDoubleCid);
680}
681
682} // namespace dart
#define EXPECT(type, expectedAlignment, expectedSize)
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
GraphEntryInstr * graph_entry() const
Definition: flow_graph.h:268
FunctionEntryInstr * normal_entry() const
Definition: il.h:2001
bool TryMatch(std::initializer_list< MatchCode > match_codes, MatchOpCode insert_before=kInvalidMatchOpCode)
static Object & Handle()
Definition: object.h:407
static RangeBoundary MinConstant(RangeSize size)
static constexpr int64_t kMin
static RangeBoundary JoinMax(RangeBoundary a, RangeBoundary b, RangeBoundary::RangeSize size)
static RangeBoundary IntersectionMin(RangeBoundary a, RangeBoundary b)
static RangeBoundary IntersectionMax(RangeBoundary a, RangeBoundary b)
int64_t ConstantValue() const
static RangeBoundary JoinMin(RangeBoundary a, RangeBoundary b, RangeBoundary::RangeSize size)
static constexpr int64_t kMax
static RangeBoundary MaxConstant(RangeSize size)
static RangeBoundary FromConstant(int64_t val)
static int64_t ConstantAbsMax(const Range *range)
static bool OnlyNegativeOrZero(const Range &a, const Range &b)
bool IsPositive() const
void set_max(const RangeBoundary &value)
static void Shr(const Range *left_range, const Range *right_range, RangeBoundary *min, RangeBoundary *max)
bool IsWithin(int64_t min_int, int64_t max_int) const
static bool OnlyPositiveOrZero(const Range &a, const Range &b)
static bool IsUnknown(const Range *other)
const RangeBoundary & min() const
static void BinaryOp(const Token::Kind op, const Range *left_range, const Range *right_range, Definition *left_defn, Range *result)
const RangeBoundary & max() const
static Range Full(RangeBoundary::RangeSize size)
void Clamp(RangeBoundary::RangeSize size)
static void Shl(const Range *left_range, const Range *right_range, RangeBoundary *min, RangeBoundary *max)
void set_min(const RangeBoundary &value)
bool OnlyLessThanOrEqualTo(int64_t val) const
bool Overlaps(int64_t min_int, int64_t max_int) const
FlowGraph * RunPasses(std::initializer_list< CompilerPass::Id > passes)
#define ASSERT(E)
GAsyncResult * result
Dart_NativeFunction function
Definition: fuchsia.cc:51
constexpr word kSmiMin
Definition: runtime_api.h:306
constexpr word kSmiMax
Definition: runtime_api.h:305
constexpr intptr_t kSmiBits
Definition: runtime_api.h:301
Definition: dart_vm.cc:33
constexpr int64_t kMaxInt64
Definition: globals.h:486
static bool Equals(const Object &expected, const Object &actual)
constexpr int64_t kMinInt64
Definition: globals.h:485
LibraryPtr LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri)
constexpr int32_t kMinInt32
Definition: globals.h:482
ObjectPtr Invoke(const Library &lib, const char *name)
FunctionPtr GetFunction(const Library &lib, const char *name)
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
TEST_CASE(DirectoryCurrent)
constexpr int32_t kMaxInt32
Definition: globals.h:483
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SIT bool all(const Vec< 1, T > &x)
Definition: SkVx.h:582
#define TEST_RANGE_AND(l_min, l_max, r_min, r_max, result_min, result_max)
#define TEST_RANGE_SUB(l_min, l_max, r_min, r_max, result_min, result_max)
#define TEST_RANGE_ADD(l_min, l_max, r_min, r_max, result_min, result_max)
#define TEST_RANGE_OP(Op, l_min, l_max, r_min, r_max, result_min, result_max)
#define TEST_RANGE_OP_SMI(Op, l_min, l_max, r_min, r_max, res_min, res_max)
#define ISOLATE_UNIT_TEST_CASE(name)
Definition: unit_test.h:64