1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <functional>
6
7 #include "src/base/overflowing-math.h"
8 #include "src/compiler/js-operator.h"
9 #include "src/compiler/node-properties.h"
10 #include "src/compiler/operator-properties.h"
11 #include "src/compiler/simplified-operator.h"
12 #include "src/objects/objects-inl.h"
13 #include "test/common/types-fuzz.h"
14 #include "test/unittests/compiler/graph-unittest.h"
15
16 namespace v8 {
17 namespace internal {
18 namespace compiler {
19
20 // TODO(titzer): generate a large set of deterministic inputs for these tests.
21 class TyperTest : public TypedGraphTest {
22 public:
TyperTest()23 TyperTest()
24 : TypedGraphTest(3),
25 broker_(isolate(), zone()),
26 operation_typer_(&broker_, zone()),
27 types_(zone(), isolate(), random_number_generator()),
28 javascript_(zone()),
29 simplified_(zone()) {
30 context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start());
31 rng_ = random_number_generator();
32
33 integers.push_back(0);
34 integers.push_back(0);
35 integers.push_back(-1);
36 integers.push_back(+1);
37 integers.push_back(-V8_INFINITY);
38 integers.push_back(+V8_INFINITY);
39 for (int i = 0; i < 5; ++i) {
40 double x = rng_->NextInt();
41 integers.push_back(x);
42 x *= rng_->NextInt();
43 if (!IsMinusZero(x)) integers.push_back(x);
44 }
45
46 int32s.push_back(0);
47 int32s.push_back(0);
48 int32s.push_back(-1);
49 int32s.push_back(+1);
50 int32s.push_back(kMinInt);
51 int32s.push_back(kMaxInt);
52 for (int i = 0; i < 10; ++i) {
53 int32s.push_back(rng_->NextInt());
54 }
55 }
56
57 const int kRepetitions = 50;
58
59 JSHeapBroker broker_;
60 OperationTyper operation_typer_;
61 Types types_;
62 JSOperatorBuilder javascript_;
63 SimplifiedOperatorBuilder simplified_;
64 Node* context_node_;
65 v8::base::RandomNumberGenerator* rng_;
66 std::vector<double> integers;
67 std::vector<double> int32s;
68
TypeUnaryOp(const Operator * op,Type type0)69 Type TypeUnaryOp(const Operator* op, Type type0) {
70 Node* p0 = Parameter(0);
71 NodeProperties::SetType(p0, type0);
72 std::vector<Node*> inputs;
73 inputs.push_back(p0);
74 if (OperatorProperties::HasContextInput(op)) {
75 inputs.push_back(context_node_);
76 }
77 for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op); i++) {
78 inputs.push_back(EmptyFrameState());
79 }
80 for (int i = 0; i < op->EffectInputCount(); i++) {
81 inputs.push_back(graph()->start());
82 }
83 for (int i = 0; i < op->ControlInputCount(); i++) {
84 inputs.push_back(graph()->start());
85 }
86 Node* n = graph()->NewNode(op, static_cast<int>(inputs.size()),
87 &(inputs.front()));
88 return NodeProperties::GetType(n);
89 }
90
UndefinedConstant()91 Node* UndefinedConstant() {
92 Handle<HeapObject> value = isolate()->factory()->undefined_value();
93 return graph()->NewNode(common()->HeapConstant(value));
94 }
95
TypeBinaryOp(const Operator * op,Type lhs,Type rhs)96 Type TypeBinaryOp(const Operator* op, Type lhs, Type rhs) {
97 Node* p0 = Parameter(0);
98 Node* p1 = Parameter(1);
99 NodeProperties::SetType(p0, lhs);
100 NodeProperties::SetType(p1, rhs);
101 std::vector<Node*> inputs;
102 inputs.push_back(p0);
103 inputs.push_back(p1);
104 if (JSOperator::IsBinaryWithFeedback(op->opcode())) {
105 inputs.push_back(UndefinedConstant()); // Feedback vector.
106 }
107 if (OperatorProperties::HasContextInput(op)) {
108 inputs.push_back(context_node_);
109 }
110 for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op); i++) {
111 inputs.push_back(EmptyFrameState());
112 }
113 for (int i = 0; i < op->EffectInputCount(); i++) {
114 inputs.push_back(graph()->start());
115 }
116 for (int i = 0; i < op->ControlInputCount(); i++) {
117 inputs.push_back(graph()->start());
118 }
119 Node* n = graph()->NewNode(op, static_cast<int>(inputs.size()),
120 &(inputs.front()));
121 return NodeProperties::GetType(n);
122 }
123
RandomRange(bool int32=false)124 Type RandomRange(bool int32 = false) {
125 std::vector<double>& numbers = int32 ? int32s : integers;
126 double i = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
127 double j = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
128 return NewRange(i, j);
129 }
130
NewRange(double i,double j)131 Type NewRange(double i, double j) {
132 if (i > j) std::swap(i, j);
133 return Type::Range(i, j, zone());
134 }
135
RandomInt(double min,double max)136 double RandomInt(double min, double max) {
137 switch (rng_->NextInt(4)) {
138 case 0:
139 return min;
140 case 1:
141 return max;
142 default:
143 break;
144 }
145 if (min == +V8_INFINITY) return +V8_INFINITY;
146 if (max == -V8_INFINITY) return -V8_INFINITY;
147 if (min == -V8_INFINITY && max == +V8_INFINITY) {
148 return rng_->NextInt() * static_cast<double>(rng_->NextInt());
149 }
150 double result = nearbyint(min + (max - min) * rng_->NextDouble());
151 if (IsMinusZero(result)) return 0;
152 if (std::isnan(result)) return rng_->NextInt(2) ? min : max;
153 DCHECK(min <= result && result <= max);
154 return result;
155 }
156
RandomInt(const RangeType * range)157 double RandomInt(const RangeType* range) {
158 return RandomInt(range->Min(), range->Max());
159 }
160
RandomSubtype(Type type)161 Type RandomSubtype(Type type) {
162 Type subtype;
163 do {
164 subtype = types_.Fuzz();
165 } while (!subtype.Is(type));
166 return subtype;
167 }
168
169 // Careful, this function runs O(max_width^5) trials.
170 template <class BinaryFunction>
TestBinaryArithOpCloseToZero(const Operator * op,BinaryFunction opfun,int max_width)171 void TestBinaryArithOpCloseToZero(const Operator* op, BinaryFunction opfun,
172 int max_width) {
173 const int min_min = -2 - max_width / 2;
174 const int max_min = 2 + max_width / 2;
175 for (int width = 0; width < max_width; width++) {
176 for (int lmin = min_min; lmin <= max_min; lmin++) {
177 for (int rmin = min_min; rmin <= max_min; rmin++) {
178 Type r1 = NewRange(lmin, lmin + width);
179 Type r2 = NewRange(rmin, rmin + width);
180 Type expected_type = TypeBinaryOp(op, r1, r2);
181
182 for (int x1 = lmin; x1 < lmin + width; x1++) {
183 for (int x2 = rmin; x2 < rmin + width; x2++) {
184 double result_value = opfun(x1, x2);
185 Type result_type = Type::Constant(
186 &broker_, isolate()->factory()->NewNumber(result_value),
187 zone());
188 EXPECT_TRUE(result_type.Is(expected_type));
189 }
190 }
191 }
192 }
193 }
194 }
195
196 template <class BinaryFunction>
TestBinaryArithOp(const Operator * op,BinaryFunction opfun)197 void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) {
198 TestBinaryArithOpCloseToZero(op, opfun, 8);
199 for (int i = 0; i < 100; ++i) {
200 Type r1 = RandomRange();
201 Type r2 = RandomRange();
202 Type expected_type = TypeBinaryOp(op, r1, r2);
203 for (int j = 0; j < 10; j++) {
204 double x1 = RandomInt(r1.AsRange());
205 double x2 = RandomInt(r2.AsRange());
206 double result_value = opfun(x1, x2);
207 Type result_type = Type::Constant(
208 &broker_, isolate()->factory()->NewNumber(result_value), zone());
209 EXPECT_TRUE(result_type.Is(expected_type));
210 }
211 }
212 // Test extreme cases.
213 double x1 = +1e-308;
214 double x2 = -1e-308;
215 Type r1 =
216 Type::Constant(&broker_, isolate()->factory()->NewNumber(x1), zone());
217 Type r2 =
218 Type::Constant(&broker_, isolate()->factory()->NewNumber(x2), zone());
219 Type expected_type = TypeBinaryOp(op, r1, r2);
220 double result_value = opfun(x1, x2);
221 Type result_type = Type::Constant(
222 &broker_, isolate()->factory()->NewNumber(result_value), zone());
223 EXPECT_TRUE(result_type.Is(expected_type));
224 }
225
226 template <class BinaryFunction>
TestBinaryCompareOp(const Operator * op,BinaryFunction opfun)227 void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) {
228 for (int i = 0; i < 100; ++i) {
229 Type r1 = RandomRange();
230 Type r2 = RandomRange();
231 Type expected_type = TypeBinaryOp(op, r1, r2);
232 for (int j = 0; j < 10; j++) {
233 double x1 = RandomInt(r1.AsRange());
234 double x2 = RandomInt(r2.AsRange());
235 bool result_value = opfun(x1, x2);
236 Type result_type =
237 Type::Constant(&broker_,
238 result_value ? isolate()->factory()->true_value()
239 : isolate()->factory()->false_value(),
240 zone());
241 EXPECT_TRUE(result_type.Is(expected_type));
242 }
243 }
244 }
245
246 template <class BinaryFunction>
TestBinaryBitOp(const Operator * op,BinaryFunction opfun)247 void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) {
248 for (int i = 0; i < 100; ++i) {
249 Type r1 = RandomRange(true);
250 Type r2 = RandomRange(true);
251 Type expected_type = TypeBinaryOp(op, r1, r2);
252 for (int j = 0; j < 10; j++) {
253 int32_t x1 = static_cast<int32_t>(RandomInt(r1.AsRange()));
254 int32_t x2 = static_cast<int32_t>(RandomInt(r2.AsRange()));
255 double result_value = opfun(x1, x2);
256 Type result_type = Type::Constant(
257 &broker_, isolate()->factory()->NewNumber(result_value), zone());
258 EXPECT_TRUE(result_type.Is(expected_type));
259 }
260 }
261 }
262
263 using UnaryTyper = std::function<Type(Type)>;
264 using BinaryTyper = std::function<Type(Type, Type)>;
265
TestUnaryMonotonicity(UnaryTyper typer,Type upper1=Type::Any ())266 void TestUnaryMonotonicity(UnaryTyper typer, Type upper1 = Type::Any()) {
267 Type type1 = Type::Intersect(types_.Fuzz(), upper1, zone());
268 DCHECK(type1.Is(upper1));
269 Type type = typer(type1);
270
271 Type subtype1 = RandomSubtype(type1);
272 Type subtype = typer(subtype1);
273
274 EXPECT_TRUE(subtype.Is(type));
275 }
276
TestBinaryMonotonicity(BinaryTyper typer,Type upper1=Type::Any (),Type upper2=Type::Any ())277 void TestBinaryMonotonicity(BinaryTyper typer, Type upper1 = Type::Any(),
278 Type upper2 = Type::Any()) {
279 Type type1 = Type::Intersect(types_.Fuzz(), upper1, zone());
280 DCHECK(type1.Is(upper1));
281 Type type2 = Type::Intersect(types_.Fuzz(), upper2, zone());
282 DCHECK(type2.Is(upper2));
283 Type type = typer(type1, type2);
284
285 Type subtype1 = RandomSubtype(type1);
286 Type subtype2 = RandomSubtype(type2);
287 Type subtype = typer(subtype1, subtype2);
288
289 EXPECT_TRUE(subtype.Is(type));
290 }
291
TestUnaryMonotonicity(const Operator * op,Type upper1=Type::Any ())292 void TestUnaryMonotonicity(const Operator* op, Type upper1 = Type::Any()) {
293 UnaryTyper typer = [&](Type type1) { return TypeUnaryOp(op, type1); };
294 for (int i = 0; i < kRepetitions; ++i) {
295 TestUnaryMonotonicity(typer, upper1);
296 }
297 }
298
TestBinaryMonotonicity(const Operator * op,Type upper1=Type::Any (),Type upper2=Type::Any ())299 void TestBinaryMonotonicity(const Operator* op, Type upper1 = Type::Any(),
300 Type upper2 = Type::Any()) {
301 BinaryTyper typer = [&](Type type1, Type type2) {
302 return TypeBinaryOp(op, type1, type2);
303 };
304 for (int i = 0; i < kRepetitions; ++i) {
305 TestBinaryMonotonicity(typer, upper1, upper2);
306 }
307 }
308 };
309
310
311 namespace {
312
shift_left(int32_t x,int32_t y)313 int32_t shift_left(int32_t x, int32_t y) {
314 return static_cast<uint32_t>(x) << (y & 0x1F);
315 }
shift_right(int32_t x,int32_t y)316 int32_t shift_right(int32_t x, int32_t y) { return x >> (y & 0x1F); }
bit_or(int32_t x,int32_t y)317 int32_t bit_or(int32_t x, int32_t y) { return x | y; }
bit_and(int32_t x,int32_t y)318 int32_t bit_and(int32_t x, int32_t y) { return x & y; }
bit_xor(int32_t x,int32_t y)319 int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; }
divide_double_double(double x,double y)320 double divide_double_double(double x, double y) { return base::Divide(x, y); }
modulo_double_double(double x,double y)321 double modulo_double_double(double x, double y) { return Modulo(x, y); }
322
FeedbackSourceWithOneBinarySlot(TyperTest * R)323 FeedbackSource FeedbackSourceWithOneBinarySlot(TyperTest* R) {
324 return FeedbackSource{
325 FeedbackVector::NewWithOneBinarySlotForTesting(R->zone(), R->isolate()),
326 FeedbackSlot{0}};
327 }
328
FeedbackSourceWithOneCompareSlot(TyperTest * R)329 FeedbackSource FeedbackSourceWithOneCompareSlot(TyperTest* R) {
330 return FeedbackSource{
331 FeedbackVector::NewWithOneCompareSlotForTesting(R->zone(), R->isolate()),
332 FeedbackSlot{0}};
333 }
334
335 } // namespace
336
337
338 //------------------------------------------------------------------------------
339 // Soundness
340 // For simplicity, we currently only test soundness on expression operators
341 // that have a direct equivalent in C++. Also, testing is currently limited
342 // to ranges as input types.
343
TEST_F(TyperTest,TypeJSAdd)344 TEST_F(TyperTest, TypeJSAdd) {
345 TestBinaryArithOp(javascript_.Add(FeedbackSourceWithOneBinarySlot(this)),
346 std::plus<double>());
347 }
348
TEST_F(TyperTest,TypeJSSubtract)349 TEST_F(TyperTest, TypeJSSubtract) {
350 TestBinaryArithOp(javascript_.Subtract(FeedbackSourceWithOneBinarySlot(this)),
351 std::minus<double>());
352 }
353
TEST_F(TyperTest,TypeJSMultiply)354 TEST_F(TyperTest, TypeJSMultiply) {
355 TestBinaryArithOp(javascript_.Multiply(FeedbackSourceWithOneBinarySlot(this)),
356 std::multiplies<double>());
357 }
358
TEST_F(TyperTest,TypeJSDivide)359 TEST_F(TyperTest, TypeJSDivide) {
360 TestBinaryArithOp(javascript_.Divide(FeedbackSourceWithOneBinarySlot(this)),
361 divide_double_double);
362 }
363
TEST_F(TyperTest,TypeJSModulus)364 TEST_F(TyperTest, TypeJSModulus) {
365 TestBinaryArithOp(javascript_.Modulus(FeedbackSourceWithOneBinarySlot(this)),
366 modulo_double_double);
367 }
368
TEST_F(TyperTest,TypeJSBitwiseOr)369 TEST_F(TyperTest, TypeJSBitwiseOr) {
370 TestBinaryBitOp(javascript_.BitwiseOr(FeedbackSourceWithOneBinarySlot(this)),
371 bit_or);
372 }
373
TEST_F(TyperTest,TypeJSBitwiseAnd)374 TEST_F(TyperTest, TypeJSBitwiseAnd) {
375 TestBinaryBitOp(javascript_.BitwiseAnd(FeedbackSourceWithOneBinarySlot(this)),
376 bit_and);
377 }
378
TEST_F(TyperTest,TypeJSBitwiseXor)379 TEST_F(TyperTest, TypeJSBitwiseXor) {
380 TestBinaryBitOp(javascript_.BitwiseXor(FeedbackSourceWithOneBinarySlot(this)),
381 bit_xor);
382 }
383
TEST_F(TyperTest,TypeJSShiftLeft)384 TEST_F(TyperTest, TypeJSShiftLeft) {
385 TestBinaryBitOp(javascript_.ShiftLeft(FeedbackSourceWithOneBinarySlot(this)),
386 shift_left);
387 }
388
TEST_F(TyperTest,TypeJSShiftRight)389 TEST_F(TyperTest, TypeJSShiftRight) {
390 TestBinaryBitOp(javascript_.ShiftRight(FeedbackSourceWithOneBinarySlot(this)),
391 shift_right);
392 }
393
TEST_F(TyperTest,TypeJSLessThan)394 TEST_F(TyperTest, TypeJSLessThan) {
395 TestBinaryCompareOp(
396 javascript_.LessThan(FeedbackSourceWithOneCompareSlot(this)),
397 std::less<double>());
398 }
399
TEST_F(TyperTest,TypeNumberLessThan)400 TEST_F(TyperTest, TypeNumberLessThan) {
401 TestBinaryCompareOp(simplified_.NumberLessThan(), std::less<double>());
402 }
403
TEST_F(TyperTest,TypeSpeculativeNumberLessThan)404 TEST_F(TyperTest, TypeSpeculativeNumberLessThan) {
405 TestBinaryCompareOp(simplified_.SpeculativeNumberLessThan(
406 NumberOperationHint::kNumberOrOddball),
407 std::less<double>());
408 }
409
TEST_F(TyperTest,TypeJSLessThanOrEqual)410 TEST_F(TyperTest, TypeJSLessThanOrEqual) {
411 TestBinaryCompareOp(
412 javascript_.LessThanOrEqual(FeedbackSourceWithOneCompareSlot(this)),
413 std::less_equal<double>());
414 }
415
TEST_F(TyperTest,TypeNumberLessThanOrEqual)416 TEST_F(TyperTest, TypeNumberLessThanOrEqual) {
417 TestBinaryCompareOp(simplified_.NumberLessThanOrEqual(),
418 std::less_equal<double>());
419 }
420
TEST_F(TyperTest,TypeSpeculativeNumberLessThanOrEqual)421 TEST_F(TyperTest, TypeSpeculativeNumberLessThanOrEqual) {
422 TestBinaryCompareOp(simplified_.SpeculativeNumberLessThanOrEqual(
423 NumberOperationHint::kNumberOrOddball),
424 std::less_equal<double>());
425 }
426
TEST_F(TyperTest,TypeJSGreaterThan)427 TEST_F(TyperTest, TypeJSGreaterThan) {
428 TestBinaryCompareOp(
429 javascript_.GreaterThan(FeedbackSourceWithOneCompareSlot(this)),
430 std::greater<double>());
431 }
432
433
TEST_F(TyperTest,TypeJSGreaterThanOrEqual)434 TEST_F(TyperTest, TypeJSGreaterThanOrEqual) {
435 TestBinaryCompareOp(
436 javascript_.GreaterThanOrEqual(FeedbackSourceWithOneCompareSlot(this)),
437 std::greater_equal<double>());
438 }
439
TEST_F(TyperTest,TypeJSEqual)440 TEST_F(TyperTest, TypeJSEqual) {
441 TestBinaryCompareOp(javascript_.Equal(FeedbackSourceWithOneCompareSlot(this)),
442 std::equal_to<double>());
443 }
444
TEST_F(TyperTest,TypeNumberEqual)445 TEST_F(TyperTest, TypeNumberEqual) {
446 TestBinaryCompareOp(simplified_.NumberEqual(), std::equal_to<double>());
447 }
448
TEST_F(TyperTest,TypeSpeculativeNumberEqual)449 TEST_F(TyperTest, TypeSpeculativeNumberEqual) {
450 TestBinaryCompareOp(
451 simplified_.SpeculativeNumberEqual(NumberOperationHint::kNumberOrOddball),
452 std::equal_to<double>());
453 }
454
455 // For numbers there's no difference between strict and non-strict equality.
TEST_F(TyperTest,TypeJSStrictEqual)456 TEST_F(TyperTest, TypeJSStrictEqual) {
457 TestBinaryCompareOp(
458 javascript_.StrictEqual(FeedbackSourceWithOneCompareSlot(this)),
459 std::equal_to<double>());
460 }
461
462 //------------------------------------------------------------------------------
463 // Typer Monotonicity
464
465 // JS UNOPs without hint
466 #define TEST_MONOTONICITY(name) \
467 TEST_F(TyperTest, Monotonicity_##name) { \
468 TestUnaryMonotonicity(javascript_.name()); \
469 }
470 TEST_MONOTONICITY(ToLength)
TEST_MONOTONICITY(ToName)471 TEST_MONOTONICITY(ToName)
472 TEST_MONOTONICITY(ToNumber)
473 TEST_MONOTONICITY(ToObject)
474 TEST_MONOTONICITY(ToString)
475 #undef TEST_MONOTONICITY
476
477 // JS compare ops.
478 #define TEST_MONOTONICITY(name) \
479 TEST_F(TyperTest, Monotonicity_##name) { \
480 TestBinaryMonotonicity( \
481 javascript_.name(FeedbackSourceWithOneCompareSlot(this))); \
482 }
483 TEST_MONOTONICITY(Equal)
484 TEST_MONOTONICITY(StrictEqual)
485 TEST_MONOTONICITY(LessThan)
486 TEST_MONOTONICITY(GreaterThan)
487 TEST_MONOTONICITY(LessThanOrEqual)
488 TEST_MONOTONICITY(GreaterThanOrEqual)
489 #undef TEST_MONOTONICITY
490
491 // JS binary ops.
492 #define TEST_MONOTONICITY(name) \
493 TEST_F(TyperTest, Monotonicity_##name) { \
494 TestBinaryMonotonicity( \
495 javascript_.name(FeedbackSourceWithOneBinarySlot(this))); \
496 }
497 TEST_MONOTONICITY(Add)
498 TEST_MONOTONICITY(BitwiseAnd)
499 TEST_MONOTONICITY(BitwiseOr)
500 TEST_MONOTONICITY(BitwiseXor)
501 TEST_MONOTONICITY(Divide)
502 TEST_MONOTONICITY(Modulus)
503 TEST_MONOTONICITY(Multiply)
504 TEST_MONOTONICITY(ShiftLeft)
505 TEST_MONOTONICITY(ShiftRight)
506 TEST_MONOTONICITY(ShiftRightLogical)
507 TEST_MONOTONICITY(Subtract)
508 #undef TEST_MONOTONICITY
509
510 TEST_F(TyperTest, Monotonicity_InstanceOf) {
511 TestBinaryMonotonicity(javascript_.InstanceOf(FeedbackSource()));
512 }
513
TEST_F(TyperTest,Monotonicity_OrdinaryHasInstance)514 TEST_F(TyperTest, Monotonicity_OrdinaryHasInstance) {
515 TestBinaryMonotonicity(javascript_.OrdinaryHasInstance());
516 }
517
518 // SIMPLIFIED UNOPs without hint
519 #define TEST_MONOTONICITY(name) \
520 TEST_F(TyperTest, Monotonicity_##name) { \
521 TestUnaryMonotonicity(simplified_.name()); \
522 }
523 TEST_MONOTONICITY(ObjectIsDetectableCallable)
TEST_MONOTONICITY(ObjectIsNaN)524 TEST_MONOTONICITY(ObjectIsNaN)
525 TEST_MONOTONICITY(ObjectIsNonCallable)
526 TEST_MONOTONICITY(ObjectIsNumber)
527 TEST_MONOTONICITY(ObjectIsReceiver)
528 TEST_MONOTONICITY(ObjectIsSmi)
529 TEST_MONOTONICITY(ObjectIsString)
530 TEST_MONOTONICITY(ObjectIsSymbol)
531 TEST_MONOTONICITY(ObjectIsUndetectable)
532 TEST_MONOTONICITY(TypeOf)
533 TEST_MONOTONICITY(ToBoolean)
534 #undef TEST_MONOTONICITY
535
536 // SIMPLIFIED BINOPs without hint, with Number input restriction
537 #define TEST_MONOTONICITY(name) \
538 TEST_F(TyperTest, Monotonicity_##name) { \
539 TestBinaryMonotonicity(simplified_.name(), Type::Number(), \
540 Type::Number()); \
541 }
542 SIMPLIFIED_NUMBER_BINOP_LIST(TEST_MONOTONICITY)
543 #undef TEST_MONOTONICITY
544
545 // SIMPLIFIED BINOPs without hint, without input restriction
546 #define TEST_MONOTONICITY(name) \
547 TEST_F(TyperTest, Monotonicity_##name) { \
548 TestBinaryMonotonicity(simplified_.name()); \
549 }
550 TEST_MONOTONICITY(NumberLessThan)
551 TEST_MONOTONICITY(NumberLessThanOrEqual)
552 TEST_MONOTONICITY(NumberEqual)
553 TEST_MONOTONICITY(ReferenceEqual)
554 TEST_MONOTONICITY(StringEqual)
555 TEST_MONOTONICITY(StringLessThan)
556 TEST_MONOTONICITY(StringLessThanOrEqual)
557 #undef TEST_MONOTONICITY
558
559 // SIMPLIFIED BINOPs with NumberOperationHint, without input restriction
560 #define TEST_MONOTONICITY(name) \
561 TEST_F(TyperTest, Monotonicity_##name) { \
562 TestBinaryMonotonicity(simplified_.name(NumberOperationHint::kNumber)); \
563 }
564 TEST_MONOTONICITY(SpeculativeNumberEqual)
565 TEST_MONOTONICITY(SpeculativeNumberLessThan)
566 TEST_MONOTONICITY(SpeculativeNumberLessThanOrEqual)
567 #undef TEST_MONOTONICITY
568
569 // SIMPLIFIED BINOPs with NumberOperationHint, without input restriction
570 #define TEST_MONOTONICITY(name) \
571 TEST_F(TyperTest, Monotonicity_##name) { \
572 TestBinaryMonotonicity(simplified_.name(NumberOperationHint::kNumber)); \
573 }
574 SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(TEST_MONOTONICITY)
575 #undef TEST_MONOTONICITY
576
577 //------------------------------------------------------------------------------
578 // OperationTyper Monotonicity
579
580 // SIMPLIFIED UNOPs with Number input restriction
581 #define TEST_MONOTONICITY(name) \
582 TEST_F(TyperTest, Monotonicity_Operation_##name) { \
583 UnaryTyper typer = [&](Type type1) { \
584 return operation_typer_.name(type1); \
585 }; \
586 for (int i = 0; i < kRepetitions; ++i) { \
587 TestUnaryMonotonicity(typer, Type::Number()); \
588 } \
589 }
590 SIMPLIFIED_NUMBER_UNOP_LIST(TEST_MONOTONICITY)
591 #undef TEST_MONOTONICITY
592
593 // SIMPLIFIED BINOPs with Number input restriction
594 #define TEST_MONOTONICITY(name) \
595 TEST_F(TyperTest, Monotonicity_Operation_##name) { \
596 BinaryTyper typer = [&](Type type1, Type type2) { \
597 return operation_typer_.name(type1, type2); \
598 }; \
599 for (int i = 0; i < kRepetitions; ++i) { \
600 TestBinaryMonotonicity(typer, Type::Number(), Type::Number()); \
601 } \
602 }
603 SIMPLIFIED_NUMBER_BINOP_LIST(TEST_MONOTONICITY)
604 #undef TEST_MONOTONICITY
605
606 // SIMPLIFIED BINOPs without input restriction
607 #define TEST_MONOTONICITY(name) \
608 TEST_F(TyperTest, Monotonicity_Operation_##name) { \
609 BinaryTyper typer = [&](Type type1, Type type2) { \
610 return operation_typer_.name(type1, type2); \
611 }; \
612 for (int i = 0; i < kRepetitions; ++i) { \
613 TestBinaryMonotonicity(typer); \
614 } \
615 }
616 SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(TEST_MONOTONICITY)
617 #undef TEST_MONOTONICITY
618
619 TEST_F(TyperTest, Manual_Operation_NumberMax) {
__anon35a172e70402(Type type1, Type type2) 620 BinaryTyper t = [&](Type type1, Type type2) {
621 return operation_typer_.NumberMax(type1, type2);
622 };
623
624 Type zero = Type::Constant(0, zone());
625 Type zero_or_minuszero = Type::Union(zero, Type::MinusZero(), zone());
626 Type dot_five = Type::Constant(0.5, zone());
627
628 Type a = t(Type::MinusZero(), Type::MinusZero());
629 CHECK(Type::MinusZero().Is(a));
630
631 Type b = t(Type::MinusZero(), zero_or_minuszero);
632 CHECK(Type::MinusZero().Is(b));
633 CHECK(zero.Is(b));
634 CHECK(a.Is(b)); // Monotonicity.
635
636 Type c = t(zero_or_minuszero, Type::MinusZero());
637 CHECK(Type::MinusZero().Is(c));
638 CHECK(zero.Is(c));
639 CHECK(a.Is(c)); // Monotonicity.
640
641 Type d = t(zero_or_minuszero, zero_or_minuszero);
642 CHECK(Type::MinusZero().Is(d));
643 CHECK(zero.Is(d));
644 CHECK(b.Is(d)); // Monotonicity.
645 CHECK(c.Is(d)); // Monotonicity.
646
647 Type e =
648 t(Type::MinusZero(), Type::Union(Type::MinusZero(), dot_five, zone()));
649 CHECK(Type::MinusZero().Is(e));
650 CHECK(dot_five.Is(e));
651 CHECK(a.Is(e)); // Monotonicity.
652
653 Type f = t(Type::MinusZero(), zero);
654 CHECK(zero.Is(f));
655 CHECK(f.Is(b)); // Monotonicity.
656
657 Type g = t(zero, Type::MinusZero());
658 CHECK(zero.Is(g));
659 CHECK(g.Is(c)); // Monotonicity.
660
661 Type h = t(Type::Signed32(), Type::MinusZero());
662 CHECK(Type::MinusZero().Is(h));
663
664 Type i = t(Type::Signed32(), zero_or_minuszero);
665 CHECK(h.Is(i)); // Monotonicity.
666 }
667
TEST_F(TyperTest,Manual_Operation_NumberMin)668 TEST_F(TyperTest, Manual_Operation_NumberMin) {
669 BinaryTyper t = [&](Type type1, Type type2) {
670 return operation_typer_.NumberMin(type1, type2);
671 };
672
673 Type zero = Type::Constant(0, zone());
674 Type zero_or_minuszero = Type::Union(zero, Type::MinusZero(), zone());
675 Type one = Type::Constant(1, zone());
676 Type minus_dot_five = Type::Constant(-0.5, zone());
677
678 Type a = t(Type::MinusZero(), Type::MinusZero());
679 CHECK(Type::MinusZero().Is(a));
680
681 Type b = t(Type::MinusZero(), zero_or_minuszero);
682 CHECK(Type::MinusZero().Is(b));
683 CHECK(zero.Is(b));
684 CHECK(a.Is(b)); // Monotonicity.
685
686 Type c = t(zero_or_minuszero, Type::MinusZero());
687 CHECK(Type::MinusZero().Is(c));
688 CHECK(zero.Is(c));
689 CHECK(a.Is(c)); // Monotonicity.
690
691 Type d = t(zero_or_minuszero, zero_or_minuszero);
692 CHECK(Type::MinusZero().Is(d));
693 CHECK(zero.Is(d));
694 CHECK(b.Is(d)); // Monotonicity.
695 CHECK(c.Is(d)); // Monotonicity.
696
697 Type e = t(Type::MinusZero(),
698 Type::Union(Type::MinusZero(), minus_dot_five, zone()));
699 CHECK(Type::MinusZero().Is(e));
700 CHECK(minus_dot_five.Is(e));
701 CHECK(a.Is(e)); // Monotonicity.
702
703 Type f = t(Type::MinusZero(), zero);
704 CHECK(Type::MinusZero().Is(f));
705 CHECK(f.Is(b)); // Monotonicity.
706
707 Type g = t(zero, Type::MinusZero());
708 CHECK(Type::MinusZero().Is(g));
709 CHECK(g.Is(c)); // Monotonicity.
710
711 Type h = t(one, Type::MinusZero());
712 CHECK(Type::MinusZero().Is(h));
713
714 Type i = t(Type::Signed32(), Type::MinusZero());
715 CHECK(Type::MinusZero().Is(i));
716
717 Type j = t(Type::Signed32(), zero_or_minuszero);
718 CHECK(i.Is(j)); // Monotonicity.
719 }
720
721 } // namespace compiler
722 } // namespace internal
723 } // namespace v8
724