OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <functional> | 5 #include <functional> |
6 | 6 |
| 7 #include "src/codegen.h" |
7 #include "src/compiler/node-properties-inl.h" | 8 #include "src/compiler/node-properties-inl.h" |
8 #include "src/compiler/typer.h" | 9 #include "src/compiler/typer.h" |
9 #include "test/cctest/cctest.h" | 10 #include "test/cctest/cctest.h" |
10 #include "test/cctest/compiler/graph-builder-tester.h" | 11 #include "test/cctest/compiler/graph-builder-tester.h" |
11 #include "test/cctest/types-fuzz.h" | 12 #include "test/cctest/types-fuzz.h" |
12 | 13 |
13 using namespace v8::internal; | 14 using namespace v8::internal; |
14 using namespace v8::internal::compiler; | 15 using namespace v8::internal::compiler; |
15 | 16 |
16 | 17 |
17 | 18 // TODO(titzer): generate a large set of deterministic inputs for these tests. |
18 class TyperTester : public HandleAndZoneScope, public GraphAndBuilders { | 19 class TyperTester : public HandleAndZoneScope, public GraphAndBuilders { |
19 public: | 20 public: |
20 TyperTester() | 21 TyperTester() |
21 : GraphAndBuilders(main_zone()), | 22 : GraphAndBuilders(main_zone()), |
22 types_(main_zone(), isolate()), | 23 types_(main_zone(), isolate()), |
23 typer_(graph(), MaybeHandle<Context>()), | 24 typer_(graph(), MaybeHandle<Context>()), |
24 javascript_(main_zone()) { | 25 javascript_(main_zone()) { |
25 Node* s = graph()->NewNode(common()->Start(3)); | 26 Node* s = graph()->NewNode(common()->Start(3)); |
26 graph()->SetStart(s); | 27 graph()->SetStart(s); |
27 context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start()); | 28 context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start()); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
72 Node* p1 = Parameter(1); | 73 Node* p1 = Parameter(1); |
73 NodeProperties::SetBounds(p0, Bounds(lhs)); | 74 NodeProperties::SetBounds(p0, Bounds(lhs)); |
74 NodeProperties::SetBounds(p1, Bounds(rhs)); | 75 NodeProperties::SetBounds(p1, Bounds(rhs)); |
75 Node* n = graph()->NewNode( | 76 Node* n = graph()->NewNode( |
76 op, p0, p1, context_node_, graph()->start(), graph()->start()); | 77 op, p0, p1, context_node_, graph()->start(), graph()->start()); |
77 return NodeProperties::GetBounds(n).upper; | 78 return NodeProperties::GetBounds(n).upper; |
78 } | 79 } |
79 | 80 |
80 Type* RandomRange(bool int32 = false) { | 81 Type* RandomRange(bool int32 = false) { |
81 std::vector<double>& numbers = int32 ? int32s : integers; | 82 std::vector<double>& numbers = int32 ? int32s : integers; |
| 83 double i = numbers[rng_->NextInt(static_cast<int>(numbers.size()))]; |
| 84 double j = numbers[rng_->NextInt(static_cast<int>(numbers.size()))]; |
| 85 return NewRange(i, j); |
| 86 } |
| 87 |
| 88 Type* NewRange(double i, double j) { |
82 Factory* f = isolate()->factory(); | 89 Factory* f = isolate()->factory(); |
83 int i = rng_->NextInt(static_cast<int>(numbers.size())); | 90 i::Handle<i::Object> min = f->NewNumber(i); |
84 int j = rng_->NextInt(static_cast<int>(numbers.size())); | 91 i::Handle<i::Object> max = f->NewNumber(j); |
85 i::Handle<i::Object> min = f->NewNumber(numbers[i]); | |
86 i::Handle<i::Object> max = f->NewNumber(numbers[j]); | |
87 if (min->Number() > max->Number()) std::swap(min, max); | 92 if (min->Number() > max->Number()) std::swap(min, max); |
88 return Type::Range(min, max, main_zone()); | 93 return Type::Range(min, max, main_zone()); |
89 } | 94 } |
90 | 95 |
91 double RandomInt(double min, double max) { | 96 double RandomInt(double min, double max) { |
92 switch (rng_->NextInt(4)) { | 97 switch (rng_->NextInt(4)) { |
93 case 0: return min; | 98 case 0: return min; |
94 case 1: return max; | 99 case 1: return max; |
95 default: break; | 100 default: break; |
96 } | 101 } |
97 if (min == +V8_INFINITY) return +V8_INFINITY; | 102 if (min == +V8_INFINITY) return +V8_INFINITY; |
98 if (max == -V8_INFINITY) return -V8_INFINITY; | 103 if (max == -V8_INFINITY) return -V8_INFINITY; |
99 if (min == -V8_INFINITY && max == +V8_INFINITY) { | 104 if (min == -V8_INFINITY && max == +V8_INFINITY) { |
100 return rng_->NextInt() * static_cast<double>(rng_->NextInt()); | 105 return rng_->NextInt() * static_cast<double>(rng_->NextInt()); |
101 } | 106 } |
102 double result = nearbyint(min + (max - min) * rng_->NextDouble()); | 107 double result = nearbyint(min + (max - min) * rng_->NextDouble()); |
103 if (IsMinusZero(result)) return 0; | 108 if (IsMinusZero(result)) return 0; |
104 if (std::isnan(result)) return rng_->NextInt(2) ? min : max; | 109 if (std::isnan(result)) return rng_->NextInt(2) ? min : max; |
105 DCHECK(min <= result && result <= max); | 110 DCHECK(min <= result && result <= max); |
106 return result; | 111 return result; |
107 } | 112 } |
108 | 113 |
109 double RandomInt(Type::RangeType* range) { | 114 double RandomInt(Type::RangeType* range) { |
110 return RandomInt(range->Min()->Number(), range->Max()->Number()); | 115 return RandomInt(range->Min()->Number(), range->Max()->Number()); |
111 } | 116 } |
112 | 117 |
| 118 // Careful, this function runs O(max_width^5) trials. |
| 119 template <class BinaryFunction> |
| 120 void TestBinaryArithOpCloseToZero(const Operator* op, BinaryFunction opfun, |
| 121 int max_width) { |
| 122 const int min_min = -2 - max_width / 2; |
| 123 const int max_min = 2 + max_width / 2; |
| 124 for (int width = 0; width < max_width; width++) { |
| 125 for (int lmin = min_min; lmin <= max_min; lmin++) { |
| 126 for (int rmin = min_min; rmin <= max_min; rmin++) { |
| 127 Type* r1 = NewRange(lmin, lmin + width); |
| 128 Type* r2 = NewRange(rmin, rmin + width); |
| 129 Type* expected_type = TypeBinaryOp(op, r1, r2); |
| 130 |
| 131 for (int x1 = lmin; x1 < lmin + width; x1++) { |
| 132 for (int x2 = rmin; x2 < rmin + width; x2++) { |
| 133 double result_value = opfun(x1, x2); |
| 134 Type* result_type = Type::Constant( |
| 135 isolate()->factory()->NewNumber(result_value), main_zone()); |
| 136 CHECK(result_type->Is(expected_type)); |
| 137 } |
| 138 } |
| 139 } |
| 140 } |
| 141 } |
| 142 } |
| 143 |
113 template <class BinaryFunction> | 144 template <class BinaryFunction> |
114 void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) { | 145 void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) { |
| 146 TestBinaryArithOpCloseToZero(op, opfun, 8); |
115 for (int i = 0; i < 100; ++i) { | 147 for (int i = 0; i < 100; ++i) { |
116 Type::RangeType* r1 = RandomRange()->AsRange(); | 148 Type::RangeType* r1 = RandomRange()->AsRange(); |
117 Type::RangeType* r2 = RandomRange()->AsRange(); | 149 Type::RangeType* r2 = RandomRange()->AsRange(); |
118 Type* expected_type = TypeBinaryOp(op, r1, r2); | 150 Type* expected_type = TypeBinaryOp(op, r1, r2); |
119 double x1 = RandomInt(r1); | 151 for (int i = 0; i < 10; i++) { |
120 double x2 = RandomInt(r2); | 152 double x1 = RandomInt(r1); |
121 double result_value = opfun(x1, x2); | 153 double x2 = RandomInt(r2); |
122 Type* result_type = Type::Constant( | 154 double result_value = opfun(x1, x2); |
123 isolate()->factory()->NewNumber(result_value), main_zone()); | 155 Type* result_type = Type::Constant( |
124 CHECK(result_type->Is(expected_type)); | 156 isolate()->factory()->NewNumber(result_value), main_zone()); |
| 157 CHECK(result_type->Is(expected_type)); |
| 158 } |
125 } | 159 } |
126 } | 160 } |
127 | 161 |
128 template <class BinaryFunction> | 162 template <class BinaryFunction> |
129 void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) { | 163 void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) { |
130 for (int i = 0; i < 100; ++i) { | 164 for (int i = 0; i < 100; ++i) { |
131 Type::RangeType* r1 = RandomRange()->AsRange(); | 165 Type::RangeType* r1 = RandomRange()->AsRange(); |
132 Type::RangeType* r2 = RandomRange()->AsRange(); | 166 Type::RangeType* r2 = RandomRange()->AsRange(); |
133 Type* expected_type = TypeBinaryOp(op, r1, r2); | 167 Type* expected_type = TypeBinaryOp(op, r1, r2); |
134 double x1 = RandomInt(r1); | 168 for (int i = 0; i < 10; i++) { |
135 double x2 = RandomInt(r2); | 169 double x1 = RandomInt(r1); |
136 bool result_value = opfun(x1, x2); | 170 double x2 = RandomInt(r2); |
137 Type* result_type = Type::Constant(result_value ? | 171 bool result_value = opfun(x1, x2); |
138 isolate()->factory()->true_value() : | 172 Type* result_type = |
139 isolate()->factory()->false_value(), main_zone()); | 173 Type::Constant(result_value ? isolate()->factory()->true_value() |
140 CHECK(result_type->Is(expected_type)); | 174 : isolate()->factory()->false_value(), |
| 175 main_zone()); |
| 176 CHECK(result_type->Is(expected_type)); |
| 177 } |
141 } | 178 } |
142 } | 179 } |
143 | 180 |
144 template <class BinaryFunction> | 181 template <class BinaryFunction> |
145 void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) { | 182 void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) { |
146 for (int i = 0; i < 100; ++i) { | 183 for (int i = 0; i < 100; ++i) { |
147 Type::RangeType* r1 = RandomRange(true)->AsRange(); | 184 Type::RangeType* r1 = RandomRange(true)->AsRange(); |
148 Type::RangeType* r2 = RandomRange(true)->AsRange(); | 185 Type::RangeType* r2 = RandomRange(true)->AsRange(); |
149 Type* expected_type = TypeBinaryOp(op, r1, r2); | 186 Type* expected_type = TypeBinaryOp(op, r1, r2); |
150 int32_t x1 = static_cast<int32_t>(RandomInt(r1)); | 187 for (int i = 0; i < 10; i++) { |
151 int32_t x2 = static_cast<int32_t>(RandomInt(r2)); | 188 int32_t x1 = static_cast<int32_t>(RandomInt(r1)); |
152 double result_value = opfun(x1, x2); | 189 int32_t x2 = static_cast<int32_t>(RandomInt(r2)); |
153 Type* result_type = Type::Constant( | 190 double result_value = opfun(x1, x2); |
154 isolate()->factory()->NewNumber(result_value), main_zone()); | 191 Type* result_type = Type::Constant( |
155 CHECK(result_type->Is(expected_type)); | 192 isolate()->factory()->NewNumber(result_value), main_zone()); |
| 193 CHECK(result_type->Is(expected_type)); |
| 194 } |
156 } | 195 } |
157 } | 196 } |
158 | 197 |
159 Type* RandomSubtype(Type* type) { | 198 Type* RandomSubtype(Type* type) { |
160 Type* subtype; | 199 Type* subtype; |
161 do { | 200 do { |
162 subtype = types_.Fuzz(); | 201 subtype = types_.Fuzz(); |
163 } while (!subtype->Is(type)); | 202 } while (!subtype->Is(type)); |
164 return subtype; | 203 return subtype; |
165 } | 204 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 t.TestBinaryArithOp(t.javascript_.Multiply(), std::multiplies<double>()); | 248 t.TestBinaryArithOp(t.javascript_.Multiply(), std::multiplies<double>()); |
210 } | 249 } |
211 | 250 |
212 | 251 |
213 TEST(TypeJSDivide) { | 252 TEST(TypeJSDivide) { |
214 TyperTester t; | 253 TyperTester t; |
215 t.TestBinaryArithOp(t.javascript_.Divide(), std::divides<double>()); | 254 t.TestBinaryArithOp(t.javascript_.Divide(), std::divides<double>()); |
216 } | 255 } |
217 | 256 |
218 | 257 |
| 258 TEST(TypeJSModulus) { |
| 259 TyperTester t; |
| 260 t.TestBinaryArithOp(t.javascript_.Modulus(), modulo); |
| 261 } |
| 262 |
| 263 |
219 TEST(TypeJSBitwiseOr) { | 264 TEST(TypeJSBitwiseOr) { |
220 TyperTester t; | 265 TyperTester t; |
221 t.TestBinaryBitOp(t.javascript_.BitwiseOr(), bit_or); | 266 t.TestBinaryBitOp(t.javascript_.BitwiseOr(), bit_or); |
222 } | 267 } |
223 | 268 |
224 | 269 |
225 TEST(TypeJSBitwiseAnd) { | 270 TEST(TypeJSBitwiseAnd) { |
226 TyperTester t; | 271 TyperTester t; |
227 t.TestBinaryBitOp(t.javascript_.BitwiseAnd(), bit_and); | 272 t.TestBinaryBitOp(t.javascript_.BitwiseAnd(), bit_and); |
228 } | 273 } |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 V(ShiftLeft) \ | 363 V(ShiftLeft) \ |
319 V(ShiftRight) \ | 364 V(ShiftRight) \ |
320 V(ShiftRightLogical) \ | 365 V(ShiftRightLogical) \ |
321 V(Add) \ | 366 V(Add) \ |
322 V(Subtract) \ | 367 V(Subtract) \ |
323 V(Multiply) \ | 368 V(Multiply) \ |
324 V(Divide) \ | 369 V(Divide) \ |
325 V(Modulus) | 370 V(Modulus) |
326 | 371 |
327 | 372 |
328 TEST(Monotonicity) { | 373 #define TEST_FUNC(name) \ |
329 TyperTester t; | 374 TEST(Monotonicity_##name) { \ |
330 #define TEST_OP(name) \ | 375 TyperTester t; \ |
331 t.TestBinaryMonotonicity(t.javascript_.name()); | 376 t.TestBinaryMonotonicity(t.javascript_.name()); \ |
332 JSBINOP_LIST(TEST_OP) | 377 } |
333 #undef TEST_OP | 378 JSBINOP_LIST(TEST_FUNC) |
334 } | 379 #undef TEST_FUNC |
OLD | NEW |