Chromium Code Reviews| 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.CheckInt32Constant(c, *i); | |
|
Jarin
2014/09/24 15:11:21
Should not this (+ the guys below) be CheckUint32C
titzer
2014/09/24 15:53:08
Good catch. Done.
| |
| 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.CheckInt32Constant(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.CheckInt32Constant(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.CheckInt32Constant(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 |