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 <limits> | 5 #include <limits> |
6 | 6 |
7 #include "src/v8.h" | 7 #include "src/v8.h" |
8 #include "test/cctest/cctest.h" | 8 #include "test/cctest/cctest.h" |
9 #include "test/cctest/compiler/graph-builder-tester.h" | 9 #include "test/cctest/compiler/graph-builder-tester.h" |
| 10 #include "test/cctest/compiler/value-helper.h" |
10 | 11 |
11 #include "src/compiler/node-matchers.h" | 12 #include "src/compiler/node-matchers.h" |
12 #include "src/compiler/representation-change.h" | 13 #include "src/compiler/representation-change.h" |
13 #include "src/compiler/typer.h" | 14 #include "src/compiler/typer.h" |
14 | 15 |
15 using namespace v8::internal; | 16 using namespace v8::internal; |
16 using namespace v8::internal::compiler; | 17 using namespace v8::internal::compiler; |
17 | 18 |
18 namespace v8 { // for friendiness. | 19 namespace v8 { // for friendiness. |
19 namespace internal { | 20 namespace internal { |
(...skipping 24 matching lines...) Expand all Loading... |
44 JSGraph* jsgraph() { return &jsgraph_; } | 45 JSGraph* jsgraph() { return &jsgraph_; } |
45 RepresentationChanger* changer() { return &changer_; } | 46 RepresentationChanger* changer() { return &changer_; } |
46 | 47 |
47 // TODO(titzer): use ValueChecker / ValueUtil | 48 // TODO(titzer): use ValueChecker / ValueUtil |
48 void CheckInt32Constant(Node* n, int32_t expected) { | 49 void CheckInt32Constant(Node* n, int32_t expected) { |
49 Int32Matcher m(n); | 50 Int32Matcher m(n); |
50 CHECK(m.HasValue()); | 51 CHECK(m.HasValue()); |
51 CHECK_EQ(expected, m.Value()); | 52 CHECK_EQ(expected, m.Value()); |
52 } | 53 } |
53 | 54 |
| 55 void CheckUint32Constant(Node* n, uint32_t expected) { |
| 56 Uint32Matcher m(n); |
| 57 CHECK(m.HasValue()); |
| 58 CHECK_EQ(static_cast<int>(expected), static_cast<int>(m.Value())); |
| 59 } |
| 60 |
| 61 void CheckFloat64Constant(Node* n, double expected) { |
| 62 Float64Matcher m(n); |
| 63 CHECK(m.HasValue()); |
| 64 CHECK_EQ(expected, m.Value()); |
| 65 } |
| 66 |
| 67 void CheckFloat32Constant(Node* n, float expected) { |
| 68 CHECK_EQ(IrOpcode::kFloat32Constant, n->opcode()); |
| 69 float fval = OpParameter<float>(n->op()); |
| 70 CHECK_EQ(expected, fval); |
| 71 } |
| 72 |
54 void CheckHeapConstant(Node* n, HeapObject* expected) { | 73 void CheckHeapConstant(Node* n, HeapObject* expected) { |
55 HeapObjectMatcher<HeapObject> m(n); | 74 HeapObjectMatcher<HeapObject> m(n); |
56 CHECK(m.HasValue()); | 75 CHECK(m.HasValue()); |
57 CHECK_EQ(expected, *m.Value().handle()); | 76 CHECK_EQ(expected, *m.Value().handle()); |
58 } | 77 } |
59 | 78 |
60 void CheckNumberConstant(Node* n, double expected) { | 79 void CheckNumberConstant(Node* n, double expected) { |
61 NumberMatcher m(n); | 80 NumberMatcher m(n); |
62 CHECK_EQ(IrOpcode::kNumberConstant, n->opcode()); | 81 CHECK_EQ(IrOpcode::kNumberConstant, n->opcode()); |
63 CHECK(m.HasValue()); | 82 CHECK(m.HasValue()); |
(...skipping 21 matching lines...) Expand all Loading... |
85 }; | 104 }; |
86 } | 105 } |
87 } | 106 } |
88 } // namespace v8::internal::compiler | 107 } // namespace v8::internal::compiler |
89 | 108 |
90 | 109 |
91 static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64, | 110 static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64, |
92 kRepFloat32, kRepFloat64, kRepTagged}; | 111 kRepFloat32, kRepFloat64, kRepTagged}; |
93 | 112 |
94 | 113 |
95 // TODO(titzer): lift this to ValueHelper | |
96 static const double double_inputs[] = { | |
97 0.0, -0.0, 1.0, -1.0, 0.1, 1.4, -1.7, | |
98 2, 5, 6, 982983, 888, -999.8, 3.1e7, | |
99 -2e66, 2.3e124, -12e73, V8_INFINITY, -V8_INFINITY}; | |
100 | |
101 | |
102 static const int32_t int32_inputs[] = { | |
103 0, 1, -1, | |
104 2, 5, 6, | |
105 982983, 888, -999, | |
106 65535, static_cast<int32_t>(0xFFFFFFFF), static_cast<int32_t>(0x80000000)}; | |
107 | |
108 | |
109 static const uint32_t uint32_inputs[] = { | |
110 0, 1, static_cast<uint32_t>(-1), 2, 5, 6, | |
111 982983, 888, static_cast<uint32_t>(-999), 65535, 0xFFFFFFFF, 0x80000000}; | |
112 | |
113 | |
114 TEST(BoolToBit_constant) { | 114 TEST(BoolToBit_constant) { |
115 RepresentationChangerTester r; | 115 RepresentationChangerTester r; |
116 | 116 |
117 Node* true_node = r.jsgraph()->TrueConstant(); | 117 Node* true_node = r.jsgraph()->TrueConstant(); |
118 Node* true_bit = | 118 Node* true_bit = |
119 r.changer()->GetRepresentationFor(true_node, kRepTagged, kRepBit); | 119 r.changer()->GetRepresentationFor(true_node, kRepTagged, kRepBit); |
120 r.CheckInt32Constant(true_bit, 1); | 120 r.CheckInt32Constant(true_bit, 1); |
121 | 121 |
122 Node* false_node = r.jsgraph()->FalseConstant(); | 122 Node* false_node = r.jsgraph()->FalseConstant(); |
123 Node* false_bit = | 123 Node* false_bit = |
(...skipping 10 matching lines...) Expand all Loading... |
134 Node* val = r.changer()->GetRepresentationFor(node, kRepBit, kRepTagged); | 134 Node* val = r.changer()->GetRepresentationFor(node, kRepBit, kRepTagged); |
135 r.CheckHeapConstant(val, i == 0 ? r.isolate()->heap()->false_value() | 135 r.CheckHeapConstant(val, i == 0 ? r.isolate()->heap()->false_value() |
136 : r.isolate()->heap()->true_value()); | 136 : r.isolate()->heap()->true_value()); |
137 } | 137 } |
138 } | 138 } |
139 | 139 |
140 | 140 |
141 TEST(ToTagged_constant) { | 141 TEST(ToTagged_constant) { |
142 RepresentationChangerTester r; | 142 RepresentationChangerTester r; |
143 | 143 |
144 for (size_t i = 0; i < arraysize(double_inputs); i++) { | 144 { |
145 Node* n = r.jsgraph()->Float64Constant(double_inputs[i]); | 145 FOR_FLOAT64_INPUTS(i) { |
146 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged); | 146 Node* n = r.jsgraph()->Float64Constant(*i); |
147 r.CheckNumberConstant(c, double_inputs[i]); | 147 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged); |
148 } | 148 r.CheckNumberConstant(c, *i); |
149 | 149 } |
150 for (size_t i = 0; i < arraysize(double_inputs); i++) { | 150 } |
151 volatile float fval = static_cast<float>(double_inputs[i]); | 151 |
152 Node* n = r.jsgraph()->Float32Constant(fval); | 152 { |
153 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepTagged); | 153 FOR_FLOAT64_INPUTS(i) { |
154 r.CheckNumberConstant(c, fval); | 154 Node* n = r.jsgraph()->Constant(*i); |
155 } | 155 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged); |
156 | 156 r.CheckNumberConstant(c, *i); |
157 for (size_t i = 0; i < arraysize(int32_inputs); i++) { | 157 } |
158 Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]); | 158 } |
159 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, | 159 |
160 kRepTagged); | 160 { |
161 r.CheckNumberConstant(c, static_cast<double>(int32_inputs[i])); | 161 FOR_FLOAT32_INPUTS(i) { |
162 } | 162 Node* n = r.jsgraph()->Float32Constant(*i); |
163 | 163 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepTagged); |
164 for (size_t i = 0; i < arraysize(uint32_inputs); i++) { | 164 r.CheckNumberConstant(c, *i); |
165 Node* n = r.jsgraph()->Int32Constant(uint32_inputs[i]); | 165 } |
166 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32, | 166 } |
167 kRepTagged); | 167 |
168 r.CheckNumberConstant(c, static_cast<double>(uint32_inputs[i])); | 168 { |
169 } | 169 FOR_INT32_INPUTS(i) { |
170 } | 170 Node* n = r.jsgraph()->Int32Constant(*i); |
171 | 171 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, |
| 172 kRepTagged); |
| 173 r.CheckNumberConstant(c, *i); |
| 174 } |
| 175 } |
| 176 |
| 177 { |
| 178 FOR_UINT32_INPUTS(i) { |
| 179 Node* n = r.jsgraph()->Int32Constant(*i); |
| 180 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32, |
| 181 kRepTagged); |
| 182 r.CheckNumberConstant(c, *i); |
| 183 } |
| 184 } |
| 185 } |
| 186 |
| 187 |
| 188 TEST(ToFloat64_constant) { |
| 189 RepresentationChangerTester r; |
| 190 |
| 191 { |
| 192 FOR_FLOAT64_INPUTS(i) { |
| 193 Node* n = r.jsgraph()->Float64Constant(*i); |
| 194 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat64); |
| 195 CHECK_EQ(n, c); |
| 196 } |
| 197 } |
| 198 |
| 199 { |
| 200 FOR_FLOAT64_INPUTS(i) { |
| 201 Node* n = r.jsgraph()->Constant(*i); |
| 202 Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat64); |
| 203 r.CheckFloat64Constant(c, *i); |
| 204 } |
| 205 } |
| 206 |
| 207 { |
| 208 FOR_FLOAT32_INPUTS(i) { |
| 209 Node* n = r.jsgraph()->Float32Constant(*i); |
| 210 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat64); |
| 211 r.CheckFloat64Constant(c, *i); |
| 212 } |
| 213 } |
| 214 |
| 215 { |
| 216 FOR_INT32_INPUTS(i) { |
| 217 Node* n = r.jsgraph()->Int32Constant(*i); |
| 218 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, |
| 219 kRepFloat64); |
| 220 r.CheckFloat64Constant(c, *i); |
| 221 } |
| 222 } |
| 223 |
| 224 { |
| 225 FOR_UINT32_INPUTS(i) { |
| 226 Node* n = r.jsgraph()->Int32Constant(*i); |
| 227 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32, |
| 228 kRepFloat64); |
| 229 r.CheckFloat64Constant(c, *i); |
| 230 } |
| 231 } |
| 232 } |
| 233 |
| 234 |
| 235 static bool IsFloat32Int32(int32_t val) { |
| 236 return val >= -(1 << 23) && val <= (1 << 23); |
| 237 } |
| 238 |
| 239 |
| 240 static bool IsFloat32Uint32(uint32_t val) { return val <= (1 << 23); } |
| 241 |
| 242 |
| 243 TEST(ToFloat32_constant) { |
| 244 RepresentationChangerTester r; |
| 245 |
| 246 { |
| 247 FOR_FLOAT32_INPUTS(i) { |
| 248 Node* n = r.jsgraph()->Float32Constant(*i); |
| 249 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat32); |
| 250 CHECK_EQ(n, c); |
| 251 } |
| 252 } |
| 253 |
| 254 { |
| 255 FOR_FLOAT32_INPUTS(i) { |
| 256 Node* n = r.jsgraph()->Constant(*i); |
| 257 Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat32); |
| 258 r.CheckFloat32Constant(c, *i); |
| 259 } |
| 260 } |
| 261 |
| 262 { |
| 263 FOR_FLOAT32_INPUTS(i) { |
| 264 Node* n = r.jsgraph()->Float64Constant(*i); |
| 265 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat32); |
| 266 r.CheckFloat32Constant(c, *i); |
| 267 } |
| 268 } |
| 269 |
| 270 { |
| 271 FOR_INT32_INPUTS(i) { |
| 272 if (!IsFloat32Int32(*i)) continue; |
| 273 Node* n = r.jsgraph()->Int32Constant(*i); |
| 274 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, |
| 275 kRepFloat32); |
| 276 r.CheckFloat32Constant(c, *i); |
| 277 } |
| 278 } |
| 279 |
| 280 { |
| 281 FOR_UINT32_INPUTS(i) { |
| 282 if (!IsFloat32Uint32(*i)) continue; |
| 283 Node* n = r.jsgraph()->Int32Constant(*i); |
| 284 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32, |
| 285 kRepFloat32); |
| 286 r.CheckFloat32Constant(c, *i); |
| 287 } |
| 288 } |
| 289 } |
| 290 |
| 291 |
| 292 TEST(ToInt32_constant) { |
| 293 RepresentationChangerTester r; |
| 294 |
| 295 { |
| 296 FOR_INT32_INPUTS(i) { |
| 297 Node* n = r.jsgraph()->Int32Constant(*i); |
| 298 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, |
| 299 kRepWord32); |
| 300 r.CheckInt32Constant(c, *i); |
| 301 } |
| 302 } |
| 303 |
| 304 { |
| 305 FOR_INT32_INPUTS(i) { |
| 306 if (!IsFloat32Int32(*i)) continue; |
| 307 Node* n = r.jsgraph()->Float32Constant(*i); |
| 308 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeInt32, |
| 309 kRepWord32); |
| 310 r.CheckInt32Constant(c, *i); |
| 311 } |
| 312 } |
| 313 |
| 314 { |
| 315 FOR_INT32_INPUTS(i) { |
| 316 Node* n = r.jsgraph()->Float64Constant(*i); |
| 317 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeInt32, |
| 318 kRepWord32); |
| 319 r.CheckInt32Constant(c, *i); |
| 320 } |
| 321 } |
| 322 |
| 323 { |
| 324 FOR_INT32_INPUTS(i) { |
| 325 Node* n = r.jsgraph()->Constant(*i); |
| 326 Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeInt32, |
| 327 kRepWord32); |
| 328 r.CheckInt32Constant(c, *i); |
| 329 } |
| 330 } |
| 331 } |
| 332 |
| 333 |
| 334 TEST(ToUint32_constant) { |
| 335 RepresentationChangerTester r; |
| 336 |
| 337 { |
| 338 FOR_UINT32_INPUTS(i) { |
| 339 Node* n = r.jsgraph()->Int32Constant(*i); |
| 340 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32, |
| 341 kRepWord32); |
| 342 r.CheckUint32Constant(c, *i); |
| 343 } |
| 344 } |
| 345 |
| 346 { |
| 347 FOR_UINT32_INPUTS(i) { |
| 348 if (!IsFloat32Uint32(*i)) continue; |
| 349 Node* n = r.jsgraph()->Float32Constant(*i); |
| 350 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeUint32, |
| 351 kRepWord32); |
| 352 r.CheckUint32Constant(c, *i); |
| 353 } |
| 354 } |
| 355 |
| 356 { |
| 357 FOR_UINT32_INPUTS(i) { |
| 358 Node* n = r.jsgraph()->Float64Constant(*i); |
| 359 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeUint32, |
| 360 kRepWord32); |
| 361 r.CheckUint32Constant(c, *i); |
| 362 } |
| 363 } |
| 364 |
| 365 { |
| 366 FOR_UINT32_INPUTS(i) { |
| 367 Node* n = r.jsgraph()->Constant(static_cast<double>(*i)); |
| 368 Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeUint32, |
| 369 kRepWord32); |
| 370 r.CheckUint32Constant(c, *i); |
| 371 } |
| 372 } |
| 373 } |
| 374 |
172 | 375 |
173 static void CheckChange(IrOpcode::Value expected, MachineTypeUnion from, | 376 static void CheckChange(IrOpcode::Value expected, MachineTypeUnion from, |
174 MachineTypeUnion to) { | 377 MachineTypeUnion to) { |
175 RepresentationChangerTester r; | 378 RepresentationChangerTester r; |
176 | 379 |
177 Node* n = r.Parameter(); | 380 Node* n = r.Parameter(); |
178 Node* c = r.changer()->GetRepresentationFor(n, from, to); | 381 Node* c = r.changer()->GetRepresentationFor(n, from, to); |
179 | 382 |
180 CHECK_NE(c, n); | 383 CHECK_NE(c, n); |
181 CHECK_EQ(expected, c->opcode()); | 384 CHECK_EQ(expected, c->opcode()); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 kRepWord32); | 444 kRepWord32); |
242 | 445 |
243 // Float32 <-> Tagged require two changes. | 446 // Float32 <-> Tagged require two changes. |
244 CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64, | 447 CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64, |
245 IrOpcode::kChangeFloat64ToTagged, kRepFloat32, kRepTagged); | 448 IrOpcode::kChangeFloat64ToTagged, kRepFloat32, kRepTagged); |
246 CheckTwoChanges(IrOpcode::kChangeTaggedToFloat64, | 449 CheckTwoChanges(IrOpcode::kChangeTaggedToFloat64, |
247 IrOpcode::kTruncateFloat64ToFloat32, kRepTagged, kRepFloat32); | 450 IrOpcode::kTruncateFloat64ToFloat32, kRepTagged, kRepFloat32); |
248 } | 451 } |
249 | 452 |
250 | 453 |
251 // TODO(titzer): test constant folding of changes between int/float | |
252 | |
253 | |
254 TEST(SignednessInWord32) { | 454 TEST(SignednessInWord32) { |
255 RepresentationChangerTester r; | 455 RepresentationChangerTester r; |
256 | 456 |
257 // TODO(titzer): assume that uses of a word32 without a sign mean kTypeInt32. | 457 // TODO(titzer): assume that uses of a word32 without a sign mean kTypeInt32. |
258 CheckChange(IrOpcode::kChangeTaggedToInt32, kRepTagged, | 458 CheckChange(IrOpcode::kChangeTaggedToInt32, kRepTagged, |
259 kRepWord32 | kTypeInt32); | 459 kRepWord32 | kTypeInt32); |
260 CheckChange(IrOpcode::kChangeTaggedToUint32, kRepTagged, | 460 CheckChange(IrOpcode::kChangeTaggedToUint32, kRepTagged, |
261 kRepWord32 | kTypeUint32); | 461 kRepWord32 | kTypeUint32); |
262 CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64); | 462 CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64); |
263 CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64, kRepWord32); | 463 CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64, kRepWord32); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 r.CheckTypeError(kRepWord32 | kTypeUint32, kRepWord64); | 540 r.CheckTypeError(kRepWord32 | kTypeUint32, kRepWord64); |
341 | 541 |
342 for (size_t i = 0; i < arraysize(all_reps); i++) { | 542 for (size_t i = 0; i < arraysize(all_reps); i++) { |
343 for (size_t j = 0; j < arraysize(all_reps); j++) { | 543 for (size_t j = 0; j < arraysize(all_reps); j++) { |
344 if (i == j) continue; | 544 if (i == j) continue; |
345 // Only a single from representation is allowed. | 545 // Only a single from representation is allowed. |
346 r.CheckTypeError(all_reps[i] | all_reps[j], kRepTagged); | 546 r.CheckTypeError(all_reps[i] | all_reps[j], kRepTagged); |
347 } | 547 } |
348 } | 548 } |
349 } | 549 } |
OLD | NEW |