| 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 | |
| 5 | #include "vm/compiler/backend/range_analysis.h" |
| 6 | #include "vm/unit_test.h" |
| 7 | |
| 8 | namespace dart { |
| 9 | |
| 10 | TEST_CASE(RangeTests) { |
| 11 | Range* zero = |
| 12 | new Range(RangeBoundary::FromConstant(0), RangeBoundary::FromConstant(0)); |
| 13 | Range* positive = new Range(RangeBoundary::FromConstant(0), |
| 14 | RangeBoundary::FromConstant(100)); |
| 15 | Range* negative = new Range(RangeBoundary::FromConstant(-1), |
| 16 | RangeBoundary::FromConstant(-100)); |
| 17 | Range* range_x = new Range(RangeBoundary::FromConstant(-15), |
| 18 | RangeBoundary::FromConstant(100)); |
| 19 | EXPECT(positive->IsPositive()); |
| 20 | EXPECT(zero->Overlaps(0, 0)); |
| 21 | EXPECT(positive->Overlaps(0, 0)); |
| 22 | EXPECT(!negative->Overlaps(0, 0)); |
| 23 | EXPECT(range_x->Overlaps(0, 0)); |
| 24 | EXPECT(range_x->IsWithin(-15, 100)); |
| 25 | EXPECT(!range_x->IsWithin(-15, 99)); |
| 26 | EXPECT(!range_x->IsWithin(-14, 100)); |
| 27 | |
| 28 | #define TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, Clamp, res_min, \ |
| 29 | res_max) \ |
| 30 | { \ |
| 31 | RangeBoundary min, max; \ |
| 32 | Range* left_range = new Range(RangeBoundary::FromConstant(l_min), \ |
| 33 | RangeBoundary::FromConstant(l_max)); \ |
| 34 | Range* shift_range = new Range(RangeBoundary::FromConstant(r_min), \ |
| 35 | RangeBoundary::FromConstant(r_max)); \ |
| 36 | Op(left_range, shift_range, &min, &max); \ |
| 37 | min = Clamp(min); \ |
| 38 | max = Clamp(max); \ |
| 39 | EXPECT(min.Equals(res_min)); \ |
| 40 | if (FLAG_support_il_printer && !min.Equals(res_min)) { \ |
| 41 | OS::PrintErr("%s\n", min.ToCString()); \ |
| 42 | } \ |
| 43 | EXPECT(max.Equals(res_max)); \ |
| 44 | if (FLAG_support_il_printer && !max.Equals(res_max)) { \ |
| 45 | OS::PrintErr("%s\n", max.ToCString()); \ |
| 46 | } \ |
| 47 | } |
| 48 | |
| 49 | #define NO_CLAMP(b) (b) |
| 50 | #define TEST_RANGE_OP(Op, l_min, l_max, r_min, r_max, result_min, result_max) \ |
| 51 | TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, NO_CLAMP, result_min, \ |
| 52 | result_max) |
| 53 | |
| 54 | #define CLAMP_TO_SMI(b) (b.Clamp(RangeBoundary::kRangeBoundarySmi)) |
| 55 | #define TEST_RANGE_OP_SMI(Op, l_min, l_max, r_min, r_max, res_min, res_max) \ |
| 56 | TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, CLAMP_TO_SMI, res_min, res_max) |
| 57 | |
| 58 | TEST_RANGE_OP(Range::Shl, -15, 100, 0, 2, RangeBoundary(-60), |
| 59 | RangeBoundary(400)); |
| 60 | TEST_RANGE_OP(Range::Shl, -15, 100, -2, 2, RangeBoundary(-60), |
| 61 | RangeBoundary(400)); |
| 62 | TEST_RANGE_OP(Range::Shl, -15, -10, 1, 2, RangeBoundary(-60), |
| 63 | RangeBoundary(-20)); |
| 64 | TEST_RANGE_OP(Range::Shl, 5, 10, -2, 2, RangeBoundary(5), RangeBoundary(40)); |
| 65 | TEST_RANGE_OP(Range::Shl, -15, 100, 0, 64, RangeBoundary::NegativeInfinity(), |
| 66 | RangeBoundary::PositiveInfinity()); |
| 67 | TEST_RANGE_OP(Range::Shl, -1, 1, 63, 63, RangeBoundary(kMinInt64), |
| 68 | RangeBoundary::PositiveInfinity()); |
| 69 | if (kBitsPerWord == 64) { |
| 70 | TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62, |
| 71 | RangeBoundary(compiler::target::kSmiMin), |
| 72 | RangeBoundary(compiler::target::kSmiMax)); |
| 73 | TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30, RangeBoundary(-(1 << 30)), |
| 74 | RangeBoundary(1 << 30)); |
| 75 | } else { |
| 76 | TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30, |
| 77 | RangeBoundary(compiler::target::kSmiMin), |
| 78 | RangeBoundary(compiler::target::kSmiMax)); |
| 79 | TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62, |
| 80 | RangeBoundary(compiler::target::kSmiMin), |
| 81 | RangeBoundary(compiler::target::kSmiMax)); |
| 82 | } |
| 83 | TEST_RANGE_OP(Range::Shl, 0, 100, 0, 64, RangeBoundary(0), |
| 84 | RangeBoundary::PositiveInfinity()); |
| 85 | TEST_RANGE_OP(Range::Shl, -100, 0, 0, 64, RangeBoundary::NegativeInfinity(), |
| 86 | RangeBoundary(0)); |
| 87 | |
| 88 | TEST_RANGE_OP(Range::Shr, -8, 8, 1, 2, RangeBoundary(-4), RangeBoundary(4)); |
| 89 | TEST_RANGE_OP(Range::Shr, 1, 8, 1, 2, RangeBoundary(0), RangeBoundary(4)); |
| 90 | TEST_RANGE_OP(Range::Shr, -16, -8, 1, 2, RangeBoundary(-8), |
| 91 | RangeBoundary(-2)); |
| 92 | TEST_RANGE_OP(Range::Shr, 2, 4, -1, 1, RangeBoundary(1), RangeBoundary(4)); |
| 93 | TEST_RANGE_OP(Range::Shr, kMaxInt64, kMaxInt64, 0, 1, |
| 94 | RangeBoundary(kMaxInt64 >> 1), RangeBoundary(kMaxInt64)); |
| 95 | TEST_RANGE_OP(Range::Shr, kMinInt64, kMinInt64, 0, 1, |
| 96 | RangeBoundary(kMinInt64), RangeBoundary(kMinInt64 >> 1)); |
| 97 | #undef TEST_RANGE_OP |
| 98 | } |
| 99 | |
| 100 | TEST_CASE(RangeTestsInfinity) { |
| 101 | // +/- inf overflowed. |
| 102 | EXPECT(RangeBoundary::NegativeInfinity().OverflowedSmi()); |
| 103 | EXPECT(RangeBoundary::PositiveInfinity().OverflowedSmi()); |
| 104 | |
| 105 | EXPECT(RangeBoundary::NegativeInfinity().OverflowedMint()); |
| 106 | EXPECT(RangeBoundary::PositiveInfinity().OverflowedMint()); |
| 107 | |
| 108 | const Range fullInt64Range = Range::Full(RangeBoundary::kRangeBoundaryInt64); |
| 109 | |
| 110 | Range* all = new Range(RangeBoundary::NegativeInfinity(), |
| 111 | RangeBoundary::PositiveInfinity()); |
| 112 | EXPECT(all->Equals(&fullInt64Range)); |
| 113 | EXPECT(all->Overlaps(0, 0)); |
| 114 | EXPECT(all->Overlaps(-1, 1)); |
| 115 | EXPECT(!all->IsWithin(0, 100)); |
| 116 | |
| 117 | Range* positive = new Range(RangeBoundary::FromConstant(0), |
| 118 | RangeBoundary::PositiveInfinity()); |
| 119 | EXPECT(positive->Equals(&fullInt64Range)); |
| 120 | EXPECT(positive->Overlaps(0, 1)); |
| 121 | EXPECT(positive->Overlaps(1, 100)); |
| 122 | EXPECT(positive->Overlaps(-1, 0)); |
| 123 | |
| 124 | Range* negative = new Range(RangeBoundary::NegativeInfinity(), |
| 125 | RangeBoundary::FromConstant(-1)); |
| 126 | EXPECT(positive->Equals(&fullInt64Range)); |
| 127 | EXPECT(negative->Overlaps(-1, 0)); |
| 128 | EXPECT(negative->Overlaps(-2, -1)); |
| 129 | |
| 130 | Range* negpos = new Range(RangeBoundary::NegativeInfinity(), |
| 131 | RangeBoundary::FromConstant(0)); |
| 132 | EXPECT(negpos->Equals(&fullInt64Range)); |
| 133 | EXPECT(!negpos->IsPositive()); |
| 134 | |
| 135 | Range* a = new Range(RangeBoundary::NegativeInfinity(), |
| 136 | RangeBoundary::FromConstant(1)); |
| 137 | |
| 138 | Range* b = new Range(RangeBoundary::NegativeInfinity(), |
| 139 | RangeBoundary::FromConstant(31)); |
| 140 | |
| 141 | Range* c = new Range(RangeBoundary::NegativeInfinity(), |
| 142 | RangeBoundary::FromConstant(32)); |
| 143 | |
| 144 | EXPECT(a->Equals(&fullInt64Range)); |
| 145 | EXPECT(b->Equals(&fullInt64Range)); |
| 146 | EXPECT(c->Equals(&fullInt64Range)); |
| 147 | EXPECT(!c->OnlyLessThanOrEqualTo(31)); |
| 148 | |
| 149 | Range* unsatisfiable = new Range(RangeBoundary::PositiveInfinity(), |
| 150 | RangeBoundary::NegativeInfinity()); |
| 151 | EXPECT(unsatisfiable->Equals(&fullInt64Range)); |
| 152 | |
| 153 | Range* unsatisfiable_right = new Range(RangeBoundary::PositiveInfinity(), |
| 154 | RangeBoundary::FromConstant(0)); |
| 155 | EXPECT(unsatisfiable_right->Equals(&fullInt64Range)); |
| 156 | |
| 157 | Range* unsatisfiable_left = new Range(RangeBoundary::FromConstant(0), |
| 158 | RangeBoundary::NegativeInfinity()); |
| 159 | EXPECT(unsatisfiable_left->Equals(&fullInt64Range)); |
| 160 | } |
| 161 | |
| 162 | TEST_CASE(RangeUtils) { |
| 163 | // Use kMin/kMax instead of +/-inf as any range with a +/-inf bound is |
| 164 | // converted to the full int64 range due to wrap-around. |
| 165 | const RangeBoundary negativeInfinity = |
| 166 | RangeBoundary::FromConstant(RangeBoundary::kMin); |
| 167 | const RangeBoundary positiveInfinity = |
| 168 | RangeBoundary::FromConstant(RangeBoundary::kMax); |
| 169 | |
| 170 | // [-inf, +inf]. |
| 171 | const Range& range_0 = *(new Range(negativeInfinity, positiveInfinity)); |
| 172 | // [-inf, -1]. |
| 173 | const Range& range_a = |
| 174 | *(new Range(negativeInfinity, RangeBoundary::FromConstant(-1))); |
| 175 | // [-inf, 0]. |
| 176 | const Range& range_b = |
| 177 | *(new Range(negativeInfinity, RangeBoundary::FromConstant(0))); |
| 178 | // [-inf, 1]. |
| 179 | const Range& range_c = |
| 180 | *(new Range(negativeInfinity, RangeBoundary::FromConstant(1))); |
| 181 | // [-1, +inf] |
| 182 | const Range& range_d = |
| 183 | *(new Range(RangeBoundary::FromConstant(-1), positiveInfinity)); |
| 184 | // [0, +inf] |
| 185 | const Range& range_e = |
| 186 | *(new Range(RangeBoundary::FromConstant(0), positiveInfinity)); |
| 187 | // [1, +inf]. |
| 188 | const Range& range_f = |
| 189 | *(new Range(RangeBoundary::FromConstant(1), positiveInfinity)); |
| 190 | // [1, 2]. |
| 191 | const Range& range_g = *(new Range(RangeBoundary::FromConstant(1), |
| 192 | RangeBoundary::FromConstant(2))); |
| 193 | // [-1, -2]. |
| 194 | const Range& range_h = *(new Range(RangeBoundary::FromConstant(-1), |
| 195 | RangeBoundary::FromConstant(-2))); |
| 196 | // [-1, 1]. |
| 197 | const Range& range_i = *(new Range(RangeBoundary::FromConstant(-1), |
| 198 | RangeBoundary::FromConstant(1))); |
| 199 | |
| 200 | // OnlyPositiveOrZero. |
| 201 | EXPECT(!Range::OnlyPositiveOrZero(range_a, range_b)); |
| 202 | EXPECT(!Range::OnlyPositiveOrZero(range_b, range_c)); |
| 203 | EXPECT(!Range::OnlyPositiveOrZero(range_c, range_d)); |
| 204 | EXPECT(!Range::OnlyPositiveOrZero(range_d, range_e)); |
| 205 | EXPECT(Range::OnlyPositiveOrZero(range_e, range_f)); |
| 206 | EXPECT(!Range::OnlyPositiveOrZero(range_d, range_d)); |
| 207 | EXPECT(Range::OnlyPositiveOrZero(range_e, range_e)); |
| 208 | EXPECT(Range::OnlyPositiveOrZero(range_f, range_g)); |
| 209 | EXPECT(!Range::OnlyPositiveOrZero(range_g, range_h)); |
| 210 | EXPECT(!Range::OnlyPositiveOrZero(range_i, range_i)); |
| 211 | |
| 212 | // OnlyNegativeOrZero. |
| 213 | EXPECT(Range::OnlyNegativeOrZero(range_a, range_b)); |
| 214 | EXPECT(!Range::OnlyNegativeOrZero(range_b, range_c)); |
| 215 | EXPECT(Range::OnlyNegativeOrZero(range_b, range_b)); |
| 216 | EXPECT(!Range::OnlyNegativeOrZero(range_c, range_c)); |
| 217 | EXPECT(!Range::OnlyNegativeOrZero(range_c, range_d)); |
| 218 | EXPECT(!Range::OnlyNegativeOrZero(range_d, range_e)); |
| 219 | EXPECT(!Range::OnlyNegativeOrZero(range_e, range_f)); |
| 220 | EXPECT(!Range::OnlyNegativeOrZero(range_f, range_g)); |
| 221 | EXPECT(!Range::OnlyNegativeOrZero(range_g, range_h)); |
| 222 | EXPECT(Range::OnlyNegativeOrZero(range_h, range_h)); |
| 223 | EXPECT(!Range::OnlyNegativeOrZero(range_i, range_i)); |
| 224 | |
| 225 | // [-inf, +inf]. |
| 226 | EXPECT(!Range::OnlyNegativeOrZero(range_0, range_0)); |
| 227 | EXPECT(!Range::OnlyPositiveOrZero(range_0, range_0)); |
| 228 | |
| 229 | EXPECT(Range::ConstantAbsMax(&range_0) == RangeBoundary::kMax); |
| 230 | EXPECT(Range::ConstantAbsMax(&range_h) == 2); |
| 231 | EXPECT(Range::ConstantAbsMax(&range_i) == 1); |
| 232 | |
| 233 | // RangeBOundary.Equals. |
| 234 | EXPECT(RangeBoundary::FromConstant(1).Equals(RangeBoundary::FromConstant(1))); |
| 235 | EXPECT( |
| 236 | !RangeBoundary::FromConstant(2).Equals(RangeBoundary::FromConstant(1))); |
| 237 | EXPECT(RangeBoundary::PositiveInfinity().Equals( |
| 238 | RangeBoundary::PositiveInfinity())); |
| 239 | EXPECT(!RangeBoundary::PositiveInfinity().Equals( |
| 240 | RangeBoundary::NegativeInfinity())); |
| 241 | EXPECT(RangeBoundary::NegativeInfinity().Equals( |
| 242 | RangeBoundary::NegativeInfinity())); |
| 243 | EXPECT(!RangeBoundary::NegativeInfinity().Equals( |
| 244 | RangeBoundary::PositiveInfinity())); |
| 245 | EXPECT(!RangeBoundary::FromConstant(1).Equals( |
| 246 | RangeBoundary::NegativeInfinity())); |
| 247 | EXPECT(!RangeBoundary::FromConstant(1).Equals( |
| 248 | RangeBoundary::NegativeInfinity())); |
| 249 | EXPECT(!RangeBoundary::FromConstant(2).Equals( |
| 250 | RangeBoundary::PositiveInfinity())); |
| 251 | } |
| 252 | |
| 253 | TEST_CASE(RangeBinaryOp) { |
| 254 | Range* range_a = new Range(RangeBoundary::FromConstant(-1), |
| 255 | RangeBoundary::FromConstant(RangeBoundary::kMax)); |
| 256 | range_a->Clamp(RangeBoundary::kRangeBoundaryInt32); |
| 257 | EXPECT(range_a->min().ConstantValue() == -1); |
| 258 | EXPECT(range_a->max().ConstantValue() == kMaxInt32); |
| 259 | range_a->set_max(RangeBoundary::FromConstant(RangeBoundary::kMax)); |
| 260 | |
| 261 | Range* range_b = new Range(RangeBoundary::FromConstant(RangeBoundary::kMin), |
| 262 | RangeBoundary::FromConstant(1)); |
| 263 | range_b->Clamp(RangeBoundary::kRangeBoundaryInt32); |
| 264 | EXPECT(range_b->min().ConstantValue() == kMinInt32); |
| 265 | EXPECT(range_b->max().ConstantValue() == 1); |
| 266 | range_b->set_min(RangeBoundary::FromConstant(RangeBoundary::kMin)); |
| 267 | |
| 268 | { |
| 269 | Range result; |
| 270 | Range::BinaryOp(Token::kADD, range_a, range_b, NULL, &result); |
| 271 | ASSERT(!Range::IsUnknown(&result)); |
| 272 | EXPECT(!result.min().IsNegativeInfinity()); |
| 273 | EXPECT(!result.max().IsPositiveInfinity()); |
| 274 | EXPECT(result.min().Equals( |
| 275 | RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64))); |
| 276 | EXPECT(result.max().Equals( |
| 277 | RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64))); |
| 278 | } |
| 279 | |
| 280 | // Test that [5, 10] + [0, 5] = [5, 15]. |
| 281 | Range* range_c = new Range(RangeBoundary::FromConstant(5), |
| 282 | RangeBoundary::FromConstant(10)); |
| 283 | Range* range_d = |
| 284 | new Range(RangeBoundary::FromConstant(0), RangeBoundary::FromConstant(5)); |
| 285 | |
| 286 | { |
| 287 | Range result; |
| 288 | Range::BinaryOp(Token::kADD, range_c, range_d, NULL, &result); |
| 289 | ASSERT(!Range::IsUnknown(&result)); |
| 290 | EXPECT(result.min().ConstantValue() == 5); |
| 291 | EXPECT(result.max().ConstantValue() == 15); |
| 292 | } |
| 293 | |
| 294 | // Test that [0xff, 0xfff] & [0xf, 0xf] = [0x0, 0xf]. |
| 295 | Range* range_e = new Range(RangeBoundary::FromConstant(0xff), |
| 296 | RangeBoundary::FromConstant(0xfff)); |
| 297 | Range* range_f = new Range(RangeBoundary::FromConstant(0xf), |
| 298 | RangeBoundary::FromConstant(0xf)); |
| 299 | { |
| 300 | Range result; |
| 301 | Range::BinaryOp(Token::kBIT_AND, range_e, range_f, NULL, &result); |
| 302 | ASSERT(!Range::IsUnknown(&result)); |
| 303 | EXPECT(result.min().ConstantValue() == 0x0); |
| 304 | EXPECT(result.max().ConstantValue() == 0xf); |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | TEST_CASE(RangeAdd) { |
| 309 | #define TEST_RANGE_ADD(l_min, l_max, r_min, r_max, result_min, result_max) \ |
| 310 | { \ |
| 311 | RangeBoundary min, max; \ |
| 312 | Range* left_range = new Range(RangeBoundary::FromConstant(l_min), \ |
| 313 | RangeBoundary::FromConstant(l_max)); \ |
| 314 | Range* right_range = new Range(RangeBoundary::FromConstant(r_min), \ |
| 315 | RangeBoundary::FromConstant(r_max)); \ |
| 316 | EXPECT(left_range->min().ConstantValue() == l_min); \ |
| 317 | EXPECT(left_range->max().ConstantValue() == l_max); \ |
| 318 | EXPECT(right_range->min().ConstantValue() == r_min); \ |
| 319 | EXPECT(right_range->max().ConstantValue() == r_max); \ |
| 320 | Range::Add(left_range, right_range, &min, &max, NULL); \ |
| 321 | EXPECT(min.Equals(result_min)); \ |
| 322 | if (FLAG_support_il_printer && !min.Equals(result_min)) { \ |
| 323 | OS::PrintErr("%s != %s\n", min.ToCString(), result_min.ToCString()); \ |
| 324 | } \ |
| 325 | EXPECT(max.Equals(result_max)); \ |
| 326 | if (FLAG_support_il_printer && !max.Equals(result_max)) { \ |
| 327 | OS::PrintErr("%s != %s\n", max.ToCString(), result_max.ToCString()); \ |
| 328 | } \ |
| 329 | } |
| 330 | |
| 331 | // [kMaxInt32, kMaxInt32 + 15] + [10, 20] = [kMaxInt32 + 10, kMaxInt32 + 35]. |
| 332 | TEST_RANGE_ADD(static_cast<int64_t>(kMaxInt32), |
| 333 | static_cast<int64_t>(kMaxInt32) + 15, static_cast<int64_t>(10), |
| 334 | static_cast<int64_t>(20), |
| 335 | RangeBoundary(static_cast<int64_t>(kMaxInt32) + 10), |
| 336 | RangeBoundary(static_cast<int64_t>(kMaxInt32) + 35)); |
| 337 | |
| 338 | // [kMaxInt32 - 15, kMaxInt32 + 15] + [15, -15] = [kMaxInt32, kMaxInt32]. |
| 339 | TEST_RANGE_ADD(static_cast<int64_t>(kMaxInt32) - 15, |
| 340 | static_cast<int64_t>(kMaxInt32) + 15, static_cast<int64_t>(15), |
| 341 | static_cast<int64_t>(-15), |
| 342 | RangeBoundary(static_cast<int64_t>(kMaxInt32)), |
| 343 | RangeBoundary(static_cast<int64_t>(kMaxInt32))); |
| 344 | |
| 345 | // [kMaxInt32, kMaxInt32 + 15] + [10, kMaxInt64] = [kMaxInt32 + 10, +inf]. |
| 346 | TEST_RANGE_ADD(static_cast<int64_t>(kMaxInt32), |
| 347 | static_cast<int64_t>(kMaxInt32) + 15, static_cast<int64_t>(10), |
| 348 | static_cast<int64_t>(kMaxInt64), |
| 349 | RangeBoundary(static_cast<int64_t>(kMaxInt32) + 10), |
| 350 | RangeBoundary::PositiveInfinity()); |
| 351 | |
| 352 | // [kMinInt64, kMaxInt32 + 15] + [10, 20] = [kMinInt64 + 10, kMaxInt32 + 35]. |
| 353 | TEST_RANGE_ADD(static_cast<int64_t>(kMinInt64), |
| 354 | static_cast<int64_t>(kMaxInt32) + 15, static_cast<int64_t>(10), |
| 355 | static_cast<int64_t>(20), |
| 356 | RangeBoundary(static_cast<int64_t>(kMinInt64) + 10), |
| 357 | RangeBoundary(static_cast<int64_t>(kMaxInt32) + 35)); |
| 358 | |
| 359 | // [0, 0] + [kMinInt64, kMaxInt64] = [kMinInt64, kMaxInt64]. |
| 360 | TEST_RANGE_ADD(static_cast<int64_t>(0), static_cast<int64_t>(0), |
| 361 | static_cast<int64_t>(kMinInt64), |
| 362 | static_cast<int64_t>(kMaxInt64), RangeBoundary(kMinInt64), |
| 363 | RangeBoundary(kMaxInt64)); |
| 364 | |
| 365 | // Overflows. |
| 366 | |
| 367 | // [-1, 1] + [kMinInt64, kMaxInt64] = [-inf, +inf]. |
| 368 | TEST_RANGE_ADD( |
| 369 | static_cast<int64_t>(-1), static_cast<int64_t>(1), |
| 370 | static_cast<int64_t>(kMinInt64), static_cast<int64_t>(kMaxInt64), |
| 371 | RangeBoundary::NegativeInfinity(), RangeBoundary::PositiveInfinity()); |
| 372 | |
| 373 | // [kMaxInt64, kMaxInt64] + [kMaxInt64, kMaxInt64] = [-inf, +inf]. |
| 374 | TEST_RANGE_ADD( |
| 375 | static_cast<int64_t>(kMaxInt64), static_cast<int64_t>(kMaxInt64), |
| 376 | static_cast<int64_t>(kMaxInt64), static_cast<int64_t>(kMaxInt64), |
| 377 | RangeBoundary::NegativeInfinity(), RangeBoundary::PositiveInfinity()); |
| 378 | |
| 379 | // [kMaxInt64, kMaxInt64] + [1, 1] = [-inf, +inf]. |
| 380 | TEST_RANGE_ADD(static_cast<int64_t>(kMaxInt64), |
| 381 | static_cast<int64_t>(kMaxInt64), static_cast<int64_t>(1), |
| 382 | static_cast<int64_t>(1), RangeBoundary::NegativeInfinity(), |
| 383 | RangeBoundary::PositiveInfinity()); |
| 384 | |
| 385 | #undef TEST_RANGE_ADD |
| 386 | } |
| 387 | |
| 388 | TEST_CASE(RangeSub) { |
| 389 | #define TEST_RANGE_SUB(l_min, l_max, r_min, r_max, result_min, result_max) \ |
| 390 | { \ |
| 391 | RangeBoundary min, max; \ |
| 392 | Range* left_range = new Range(RangeBoundary::FromConstant(l_min), \ |
| 393 | RangeBoundary::FromConstant(l_max)); \ |
| 394 | Range* right_range = new Range(RangeBoundary::FromConstant(r_min), \ |
| 395 | RangeBoundary::FromConstant(r_max)); \ |
| 396 | EXPECT(left_range->min().ConstantValue() == l_min); \ |
| 397 | EXPECT(left_range->max().ConstantValue() == l_max); \ |
| 398 | EXPECT(right_range->min().ConstantValue() == r_min); \ |
| 399 | EXPECT(right_range->max().ConstantValue() == r_max); \ |
| 400 | Range::Sub(left_range, right_range, &min, &max, NULL); \ |
| 401 | EXPECT(min.Equals(result_min)); \ |
| 402 | if (FLAG_support_il_printer && !min.Equals(result_min)) { \ |
| 403 | OS::PrintErr("%s != %s\n", min.ToCString(), result_min.ToCString()); \ |
| 404 | } \ |
| 405 | EXPECT(max.Equals(result_max)); \ |
| 406 | if (FLAG_support_il_printer && !max.Equals(result_max)) { \ |
| 407 | OS::PrintErr("%s != %s\n", max.ToCString(), result_max.ToCString()); \ |
| 408 | } \ |
| 409 | } |
| 410 | |
| 411 | // [kMaxInt32, kMaxInt32 + 15] - [10, 20] = [kMaxInt32 - 20, kMaxInt32 + 5]. |
| 412 | TEST_RANGE_SUB(static_cast<int64_t>(kMaxInt32), |
| 413 | static_cast<int64_t>(kMaxInt32) + 15, static_cast<int64_t>(10), |
| 414 | static_cast<int64_t>(20), |
| 415 | RangeBoundary(static_cast<int64_t>(kMaxInt32) - 20), |
| 416 | RangeBoundary(static_cast<int64_t>(kMaxInt32) + 5)); |
| 417 | |
| 418 | // [kMintInt64, kMintInt64] - [1, 1] = [-inf, +inf]. |
| 419 | TEST_RANGE_SUB(static_cast<int64_t>(kMinInt64), |
| 420 | static_cast<int64_t>(kMinInt64), static_cast<int64_t>(1), |
| 421 | static_cast<int64_t>(1), RangeBoundary::NegativeInfinity(), |
| 422 | RangeBoundary::PositiveInfinity()); |
| 423 | |
| 424 | // [1, 1] - [kMintInt64, kMintInt64] = [-inf, +inf]. |
| 425 | TEST_RANGE_SUB( |
| 426 | static_cast<int64_t>(1), static_cast<int64_t>(1), |
| 427 | static_cast<int64_t>(kMinInt64), static_cast<int64_t>(kMinInt64), |
| 428 | RangeBoundary::NegativeInfinity(), RangeBoundary::PositiveInfinity()); |
| 429 | |
| 430 | // [kMaxInt32 + 10, kMaxInt32 + 20] - [-20, -20] = |
| 431 | // [kMaxInt32 + 30, kMaxInt32 + 40]. |
| 432 | TEST_RANGE_SUB(static_cast<int64_t>(kMaxInt32) + 10, |
| 433 | static_cast<int64_t>(kMaxInt32) + 20, |
| 434 | static_cast<int64_t>(-20), static_cast<int64_t>(-20), |
| 435 | RangeBoundary(static_cast<int64_t>(kMaxInt32) + 30), |
| 436 | RangeBoundary(static_cast<int64_t>(kMaxInt32) + 40)); |
| 437 | |
| 438 | #undef TEST_RANGE_SUB |
| 439 | } |
| 440 | |
| 441 | TEST_CASE(RangeAnd) { |
| 442 | #define TEST_RANGE_AND(l_min, l_max, r_min, r_max, result_min, result_max) \ |
| 443 | { \ |
| 444 | RangeBoundary min, max; \ |
| 445 | Range* left_range = new Range(RangeBoundary::FromConstant(l_min), \ |
| 446 | RangeBoundary::FromConstant(l_max)); \ |
| 447 | Range* right_range = new Range(RangeBoundary::FromConstant(r_min), \ |
| 448 | RangeBoundary::FromConstant(r_max)); \ |
| 449 | EXPECT(left_range->min().ConstantValue() == l_min); \ |
| 450 | EXPECT(left_range->max().ConstantValue() == l_max); \ |
| 451 | EXPECT(right_range->min().ConstantValue() == r_min); \ |
| 452 | EXPECT(right_range->max().ConstantValue() == r_max); \ |
| 453 | Range::And(left_range, right_range, &min, &max); \ |
| 454 | EXPECT(min.Equals(result_min)); \ |
| 455 | if (FLAG_support_il_printer && !min.Equals(result_min)) { \ |
| 456 | OS::PrintErr("%s != %s\n", min.ToCString(), result_min.ToCString()); \ |
| 457 | } \ |
| 458 | EXPECT(max.Equals(result_max)); \ |
| 459 | if (FLAG_support_il_printer && !max.Equals(result_max)) { \ |
| 460 | OS::PrintErr("%s != %s\n", max.ToCString(), result_max.ToCString()); \ |
| 461 | } \ |
| 462 | } |
| 463 | |
| 464 | // [0xff, 0xfff] & [0xf, 0xf] = [0x0, 0xf]. |
| 465 | TEST_RANGE_AND(static_cast<int64_t>(0xff), static_cast<int64_t>(0xfff), |
| 466 | static_cast<int64_t>(0xf), static_cast<int64_t>(0xf), |
| 467 | RangeBoundary(0), RangeBoundary(0xf)); |
| 468 | |
| 469 | // [0xffffffff, 0xffffffff] & [0xfffffffff, 0xfffffffff] = [0x0, 0xfffffffff]. |
| 470 | TEST_RANGE_AND( |
| 471 | static_cast<int64_t>(0xffffffff), static_cast<int64_t>(0xffffffff), |
| 472 | static_cast<int64_t>(0xfffffffff), static_cast<int64_t>(0xfffffffff), |
| 473 | RangeBoundary(0), RangeBoundary(static_cast<int64_t>(0xfffffffff))); |
| 474 | |
| 475 | // [0xffffffff, 0xffffffff] & [-20, 20] = [0x0, 0xffffffff]. |
| 476 | TEST_RANGE_AND(static_cast<int64_t>(0xffffffff), |
| 477 | static_cast<int64_t>(0xffffffff), static_cast<int64_t>(-20), |
| 478 | static_cast<int64_t>(20), RangeBoundary(0), |
| 479 | RangeBoundary(static_cast<int64_t>(0xffffffff))); |
| 480 | |
| 481 | // [-20, 20] & [0xffffffff, 0xffffffff] = [0x0, 0xffffffff]. |
| 482 | TEST_RANGE_AND(static_cast<int64_t>(-20), static_cast<int64_t>(20), |
| 483 | static_cast<int64_t>(0xffffffff), |
| 484 | static_cast<int64_t>(0xffffffff), RangeBoundary(0), |
| 485 | RangeBoundary(static_cast<int64_t>(0xffffffff))); |
| 486 | |
| 487 | // Test that [-20, 20] & [-20, 20] = [-32, 31]. |
| 488 | TEST_RANGE_AND(static_cast<int64_t>(-20), static_cast<int64_t>(20), |
| 489 | static_cast<int64_t>(-20), static_cast<int64_t>(20), |
| 490 | RangeBoundary(-32), RangeBoundary(31)); |
| 491 | |
| 492 | #undef TEST_RANGE_AND |
| 493 | } |
| 494 | |
| 495 | TEST_CASE(RangeIntersectionMinMax) { |
| 496 | // Test IntersectionMin and IntersectionMax methods which for constants are |
| 497 | // simply defined as Max/Min respectively. |
| 498 | |
| 499 | // Constants. |
| 500 | // MIN(0, 1) == 0 |
| 501 | EXPECT(RangeBoundary::IntersectionMax(RangeBoundary::FromConstant(0), |
| 502 | RangeBoundary::FromConstant(1)) |
| 503 | .ConstantValue() == 0); |
| 504 | // MIN(0, -1) == -1 |
| 505 | EXPECT(RangeBoundary::IntersectionMax(RangeBoundary::FromConstant(0), |
| 506 | RangeBoundary::FromConstant(-1)) |
| 507 | .ConstantValue() == -1); |
| 508 | |
| 509 | // MIN(1, 0) == 0 |
| 510 | EXPECT(RangeBoundary::IntersectionMax(RangeBoundary::FromConstant(1), |
| 511 | RangeBoundary::FromConstant(0)) |
| 512 | .ConstantValue() == 0); |
| 513 | // MIN(-1, 0) == -1 |
| 514 | EXPECT(RangeBoundary::IntersectionMax(RangeBoundary::FromConstant(-1), |
| 515 | RangeBoundary::FromConstant(0)) |
| 516 | .ConstantValue() == -1); |
| 517 | |
| 518 | // MAX(0, 1) == 1 |
| 519 | EXPECT(RangeBoundary::IntersectionMin(RangeBoundary::FromConstant(0), |
| 520 | RangeBoundary::FromConstant(1)) |
| 521 | .ConstantValue() == 1); |
| 522 | |
| 523 | // MAX(0, -1) == 0 |
| 524 | EXPECT(RangeBoundary::IntersectionMin(RangeBoundary::FromConstant(0), |
| 525 | RangeBoundary::FromConstant(-1)) |
| 526 | .ConstantValue() == 0); |
| 527 | |
| 528 | // MAX(1, 0) == 1 |
| 529 | EXPECT(RangeBoundary::IntersectionMin(RangeBoundary::FromConstant(1), |
| 530 | RangeBoundary::FromConstant(0)) |
| 531 | .ConstantValue() == 1); |
| 532 | // MAX(-1, 0) == 0 |
| 533 | EXPECT(RangeBoundary::IntersectionMin(RangeBoundary::FromConstant(-1), |
| 534 | RangeBoundary::FromConstant(0)) |
| 535 | .ConstantValue() == 0); |
| 536 | |
| 537 | RangeBoundary n_infinity = RangeBoundary::NegativeInfinity(); |
| 538 | RangeBoundary p_infinity = RangeBoundary::PositiveInfinity(); |
| 539 | |
| 540 | // Constants vs. infinity. |
| 541 | EXPECT(RangeBoundary::IntersectionMin(n_infinity, |
| 542 | RangeBoundary::FromConstant(-1)) |
| 543 | .ConstantValue() == -1); |
| 544 | |
| 545 | EXPECT(RangeBoundary::IntersectionMin(RangeBoundary::FromConstant(-1), |
| 546 | n_infinity) |
| 547 | .ConstantValue() == -1); |
| 548 | |
| 549 | EXPECT( |
| 550 | RangeBoundary::IntersectionMin(RangeBoundary::FromConstant(1), n_infinity) |
| 551 | .ConstantValue() == 1); |
| 552 | |
| 553 | EXPECT( |
| 554 | RangeBoundary::IntersectionMin(n_infinity, RangeBoundary::FromConstant(1)) |
| 555 | .ConstantValue() == 1); |
| 556 | |
| 557 | EXPECT(RangeBoundary::IntersectionMax(p_infinity, |
| 558 | RangeBoundary::FromConstant(-1)) |
| 559 | .ConstantValue() == -1); |
| 560 | |
| 561 | EXPECT(RangeBoundary::IntersectionMax(RangeBoundary::FromConstant(-1), |
| 562 | p_infinity) |
| 563 | .ConstantValue() == -1); |
| 564 | |
| 565 | EXPECT( |
| 566 | RangeBoundary::IntersectionMax(RangeBoundary::FromConstant(1), p_infinity) |
| 567 | .ConstantValue() == 1); |
| 568 | |
| 569 | EXPECT( |
| 570 | RangeBoundary::IntersectionMax(p_infinity, RangeBoundary::FromConstant(1)) |
| 571 | .ConstantValue() == 1); |
| 572 | } |
| 573 | |
| 574 | TEST_CASE(RangeJoinMinMax) { |
| 575 | // Test IntersectionMin and IntersectionMax methods which for constants are |
| 576 | // simply defined as Min/Max respectively. |
| 577 | const RangeBoundary::RangeSize size = RangeBoundary::kRangeBoundarySmi; |
| 578 | |
| 579 | // Constants. |
| 580 | EXPECT(RangeBoundary::JoinMax(RangeBoundary::FromConstant(0), |
| 581 | RangeBoundary::FromConstant(1), size) |
| 582 | .ConstantValue() == 1); |
| 583 | EXPECT(RangeBoundary::JoinMax(RangeBoundary::FromConstant(0), |
| 584 | RangeBoundary::FromConstant(-1), size) |
| 585 | .ConstantValue() == 0); |
| 586 | EXPECT(RangeBoundary::JoinMax(RangeBoundary::FromConstant(1), |
| 587 | RangeBoundary::FromConstant(0), size) |
| 588 | .ConstantValue() == 1); |
| 589 | EXPECT(RangeBoundary::JoinMax(RangeBoundary::FromConstant(-1), |
| 590 | RangeBoundary::FromConstant(0), size) |
| 591 | .ConstantValue() == 0); |
| 592 | EXPECT(RangeBoundary::JoinMin(RangeBoundary::FromConstant(0), |
| 593 | RangeBoundary::FromConstant(1), size) |
| 594 | .ConstantValue() == 0); |
| 595 | EXPECT(RangeBoundary::JoinMin(RangeBoundary::FromConstant(0), |
| 596 | RangeBoundary::FromConstant(-1), size) |
| 597 | .ConstantValue() == -1); |
| 598 | EXPECT(RangeBoundary::JoinMin(RangeBoundary::FromConstant(1), |
| 599 | RangeBoundary::FromConstant(0), size) |
| 600 | .ConstantValue() == 0); |
| 601 | EXPECT(RangeBoundary::JoinMin(RangeBoundary::FromConstant(-1), |
| 602 | RangeBoundary::FromConstant(0), size) |
| 603 | .ConstantValue() == -1); |
| 604 | |
| 605 | RangeBoundary n_infinity = RangeBoundary::NegativeInfinity(); |
| 606 | RangeBoundary p_infinity = RangeBoundary::PositiveInfinity(); |
| 607 | |
| 608 | // Constants vs. infinity. |
| 609 | EXPECT( |
| 610 | RangeBoundary::JoinMin(n_infinity, RangeBoundary::FromConstant(-1), size) |
| 611 | .IsMinimumOrBelow(size)); |
| 612 | |
| 613 | EXPECT( |
| 614 | RangeBoundary::JoinMin(RangeBoundary::FromConstant(-1), n_infinity, size) |
| 615 | .IsMinimumOrBelow(size)); |
| 616 | |
| 617 | EXPECT( |
| 618 | RangeBoundary::JoinMin(RangeBoundary::FromConstant(1), n_infinity, size) |
| 619 | .IsMinimumOrBelow(size)); |
| 620 | |
| 621 | EXPECT( |
| 622 | RangeBoundary::JoinMin(n_infinity, RangeBoundary::FromConstant(1), size) |
| 623 | .IsMinimumOrBelow(size)); |
| 624 | |
| 625 | EXPECT( |
| 626 | RangeBoundary::JoinMax(p_infinity, RangeBoundary::FromConstant(-1), size) |
| 627 | .IsMaximumOrAbove(size)); |
| 628 | |
| 629 | EXPECT( |
| 630 | RangeBoundary::JoinMax(RangeBoundary::FromConstant(-1), p_infinity, size) |
| 631 | .IsMaximumOrAbove(size)); |
| 632 | |
| 633 | EXPECT( |
| 634 | RangeBoundary::JoinMax(RangeBoundary::FromConstant(1), p_infinity, size) |
| 635 | .IsMaximumOrAbove(size)); |
| 636 | |
| 637 | EXPECT( |
| 638 | RangeBoundary::JoinMax(p_infinity, RangeBoundary::FromConstant(1), size) |
| 639 | .IsMaximumOrAbove(size)); |
| 640 | } |
| 641 | |
| 642 | } // namespace dart |
| 643 | |