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 3 // found in the LICENSE file. 4 5 #include <limits> 6 7 #include "src/ast/scopes.h" 8 #include "src/compiler/access-builder.h" 9 #include "src/compiler/control-builders.h" 10 #include "src/compiler/effect-control-linearizer.h" 11 #include "src/compiler/graph-visualizer.h" 12 #include "src/compiler/memory-optimizer.h" 13 #include "src/compiler/node-properties.h" 14 #include "src/compiler/pipeline.h" 15 #include "src/compiler/representation-change.h" 16 #include "src/compiler/scheduler.h" 17 #include "src/compiler/simplified-lowering.h" 18 #include "src/compiler/source-position.h" 19 #include "src/compiler/typer.h" 20 #include "src/compiler/verifier.h" 21 #include "src/execution.h" 22 #include "src/parsing/parser.h" 23 #include "src/parsing/rewriter.h" 24 #include "test/cctest/cctest.h" 25 #include "test/cctest/compiler/codegen-tester.h" 26 #include "test/cctest/compiler/function-tester.h" 27 #include "test/cctest/compiler/graph-builder-tester.h" 28 #include "test/cctest/compiler/value-helper.h" 29 30 namespace v8 { 31 namespace internal { 32 namespace compiler { 33 34 template <typename ReturnType> 35 class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> { 36 public: 37 SimplifiedLoweringTester(MachineType p0 = MachineType::None(), 38 MachineType p1 = MachineType::None()) 39 : GraphBuilderTester<ReturnType>(p0, p1), 40 typer(this->isolate(), this->graph()), 41 javascript(this->zone()), 42 jsgraph(this->isolate(), this->graph(), this->common(), &javascript, 43 this->simplified(), this->machine()), 44 source_positions(jsgraph.graph()), 45 lowering(&jsgraph, this->zone(), &source_positions) {} 46 47 Typer typer; 48 JSOperatorBuilder javascript; 49 JSGraph jsgraph; 50 SourcePositionTable source_positions; 51 SimplifiedLowering lowering; 52 53 void LowerAllNodes() { 54 this->End(); 55 typer.Run(); 56 lowering.LowerAllNodes(); 57 } 58 59 void LowerAllNodesAndLowerChanges() { 60 this->End(); 61 typer.Run(); 62 lowering.LowerAllNodes(); 63 64 Schedule* schedule = Scheduler::ComputeSchedule(this->zone(), this->graph(), 65 Scheduler::kNoFlags); 66 EffectControlLinearizer linearizer(&jsgraph, schedule, this->zone()); 67 linearizer.Run(); 68 69 MemoryOptimizer memory_optimizer(&jsgraph, this->zone()); 70 memory_optimizer.Optimize(); 71 } 72 73 void CheckNumberCall(double expected, double input) { 74 // TODO(titzer): make calls to NewNumber work in cctests. 75 if (expected <= Smi::kMinValue) return; 76 if (expected >= Smi::kMaxValue) return; 77 Handle<Object> num = factory()->NewNumber(input); 78 Object* result = this->Call(*num); 79 CHECK(factory()->NewNumber(expected)->SameValue(result)); 80 } 81 82 template <typename T> 83 T* CallWithPotentialGC() { 84 // TODO(titzer): we wrap the code in a JSFunction here to reuse the 85 // JSEntryStub; that could be done with a special prologue or other stub. 86 Handle<JSFunction> fun = FunctionTester::ForMachineGraph(this->graph(), 0); 87 Handle<Object>* args = NULL; 88 MaybeHandle<Object> result = Execution::Call( 89 this->isolate(), fun, factory()->undefined_value(), 0, args); 90 return T::cast(*result.ToHandleChecked()); 91 } 92 93 Factory* factory() { return this->isolate()->factory(); } 94 Heap* heap() { return this->isolate()->heap(); } 95 }; 96 97 98 // TODO(titzer): factor these tests out to test-run-simplifiedops.cc. 99 // TODO(titzer): test tagged representation for input to NumberToInt32. 100 TEST(RunNumberToInt32_float64) { 101 // TODO(titzer): explicit load/stores here are only because of representations 102 double input; 103 int32_t result; 104 SimplifiedLoweringTester<Object*> t; 105 FieldAccess load = {kUntaggedBase, 0, 106 Handle<Name>(), Type::Number(), 107 MachineType::Float64(), kNoWriteBarrier}; 108 Node* loaded = t.LoadField(load, t.PointerConstant(&input)); 109 NodeProperties::SetType(loaded, Type::Number()); 110 Node* convert = t.NumberToInt32(loaded); 111 FieldAccess store = {kUntaggedBase, 0, 112 Handle<Name>(), Type::Signed32(), 113 MachineType::Int32(), kNoWriteBarrier}; 114 t.StoreField(store, t.PointerConstant(&result), convert); 115 t.Return(t.jsgraph.TrueConstant()); 116 t.LowerAllNodesAndLowerChanges(); 117 t.GenerateCode(); 118 119 FOR_FLOAT64_INPUTS(i) { 120 input = *i; 121 int32_t expected = DoubleToInt32(*i); 122 t.Call(); 123 CHECK_EQ(expected, result); 124 } 125 } 126 127 128 // TODO(titzer): test tagged representation for input to NumberToUint32. 129 TEST(RunNumberToUint32_float64) { 130 // TODO(titzer): explicit load/stores here are only because of representations 131 double input; 132 uint32_t result; 133 SimplifiedLoweringTester<Object*> t; 134 FieldAccess load = {kUntaggedBase, 0, 135 Handle<Name>(), Type::Number(), 136 MachineType::Float64(), kNoWriteBarrier}; 137 Node* loaded = t.LoadField(load, t.PointerConstant(&input)); 138 NodeProperties::SetType(loaded, Type::Number()); 139 Node* convert = t.NumberToUint32(loaded); 140 FieldAccess store = {kUntaggedBase, 0, 141 Handle<Name>(), Type::Unsigned32(), 142 MachineType::Uint32(), kNoWriteBarrier}; 143 t.StoreField(store, t.PointerConstant(&result), convert); 144 t.Return(t.jsgraph.TrueConstant()); 145 t.LowerAllNodesAndLowerChanges(); 146 t.GenerateCode(); 147 148 FOR_FLOAT64_INPUTS(i) { 149 input = *i; 150 uint32_t expected = DoubleToUint32(*i); 151 t.Call(); 152 CHECK_EQ(static_cast<int32_t>(expected), static_cast<int32_t>(result)); 153 } 154 } 155 156 157 // Create a simple JSObject with a unique map. 158 static Handle<JSObject> TestObject() { 159 static int index = 0; 160 char buffer[50]; 161 v8::base::OS::SNPrintF(buffer, 50, "({'a_%d':1})", index++); 162 return Handle<JSObject>::cast(v8::Utils::OpenHandle(*CompileRun(buffer))); 163 } 164 165 166 TEST(RunLoadMap) { 167 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 168 FieldAccess access = AccessBuilder::ForMap(); 169 Node* load = t.LoadField(access, t.Parameter(0)); 170 t.Return(load); 171 172 t.LowerAllNodesAndLowerChanges(); 173 t.GenerateCode(); 174 175 Handle<JSObject> src = TestObject(); 176 Handle<Map> src_map(src->map()); 177 Object* result = t.Call(*src); // TODO(titzer): raw pointers in call 178 CHECK_EQ(*src_map, result); 179 } 180 181 182 TEST(RunStoreMap) { 183 SimplifiedLoweringTester<int32_t> t(MachineType::AnyTagged(), 184 MachineType::AnyTagged()); 185 FieldAccess access = AccessBuilder::ForMap(); 186 t.StoreField(access, t.Parameter(1), t.Parameter(0)); 187 t.Return(t.jsgraph.TrueConstant()); 188 189 t.LowerAllNodesAndLowerChanges(); 190 t.GenerateCode(); 191 192 Handle<JSObject> src = TestObject(); 193 Handle<Map> src_map(src->map()); 194 Handle<JSObject> dst = TestObject(); 195 CHECK(src->map() != dst->map()); 196 t.Call(*src_map, *dst); // TODO(titzer): raw pointers in call 197 CHECK(*src_map == dst->map()); 198 } 199 200 201 TEST(RunLoadProperties) { 202 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 203 FieldAccess access = AccessBuilder::ForJSObjectProperties(); 204 Node* load = t.LoadField(access, t.Parameter(0)); 205 t.Return(load); 206 207 t.LowerAllNodesAndLowerChanges(); 208 t.GenerateCode(); 209 210 Handle<JSObject> src = TestObject(); 211 Handle<FixedArray> src_props(src->properties()); 212 Object* result = t.Call(*src); // TODO(titzer): raw pointers in call 213 CHECK_EQ(*src_props, result); 214 } 215 216 217 TEST(RunLoadStoreMap) { 218 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged(), 219 MachineType::AnyTagged()); 220 FieldAccess access = AccessBuilder::ForMap(); 221 Node* load = t.LoadField(access, t.Parameter(0)); 222 t.StoreField(access, t.Parameter(1), load); 223 t.Return(load); 224 225 t.LowerAllNodesAndLowerChanges(); 226 t.GenerateCode(); 227 228 Handle<JSObject> src = TestObject(); 229 Handle<Map> src_map(src->map()); 230 Handle<JSObject> dst = TestObject(); 231 CHECK(src->map() != dst->map()); 232 Object* result = t.Call(*src, *dst); // TODO(titzer): raw pointers in call 233 CHECK(result->IsMap()); 234 CHECK_EQ(*src_map, result); 235 CHECK(*src_map == dst->map()); 236 } 237 238 239 TEST(RunLoadStoreFixedArrayIndex) { 240 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 241 ElementAccess access = AccessBuilder::ForFixedArrayElement(); 242 Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0)); 243 t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load); 244 t.Return(load); 245 246 t.LowerAllNodesAndLowerChanges(); 247 t.GenerateCode(); 248 249 Handle<FixedArray> array = t.factory()->NewFixedArray(2); 250 Handle<JSObject> src = TestObject(); 251 Handle<JSObject> dst = TestObject(); 252 array->set(0, *src); 253 array->set(1, *dst); 254 Object* result = t.Call(*array); 255 CHECK_EQ(*src, result); 256 CHECK_EQ(*src, array->get(0)); 257 CHECK_EQ(*src, array->get(1)); 258 } 259 260 261 TEST(RunLoadStoreArrayBuffer) { 262 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 263 const int index = 12; 264 const int array_length = 2 * index; 265 ElementAccess buffer_access = 266 AccessBuilder::ForTypedArrayElement(kExternalInt8Array, true); 267 Node* backing_store = t.LoadField( 268 AccessBuilder::ForJSArrayBufferBackingStore(), t.Parameter(0)); 269 Node* load = 270 t.LoadElement(buffer_access, backing_store, t.Int32Constant(index)); 271 t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1), 272 load); 273 t.Return(t.jsgraph.TrueConstant()); 274 275 t.LowerAllNodesAndLowerChanges(); 276 t.GenerateCode(); 277 278 Handle<JSArrayBuffer> array = t.factory()->NewJSArrayBuffer(); 279 JSArrayBuffer::SetupAllocatingData(array, t.isolate(), array_length); 280 uint8_t* data = reinterpret_cast<uint8_t*>(array->backing_store()); 281 for (int i = 0; i < array_length; i++) { 282 data[i] = i; 283 } 284 285 // TODO(titzer): raw pointers in call 286 Object* result = t.Call(*array); 287 CHECK_EQ(t.isolate()->heap()->true_value(), result); 288 for (int i = 0; i < array_length; i++) { 289 uint8_t expected = i; 290 if (i == (index + 1)) expected = index; 291 CHECK_EQ(data[i], expected); 292 } 293 } 294 295 296 TEST(RunLoadFieldFromUntaggedBase) { 297 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)}; 298 299 for (size_t i = 0; i < arraysize(smis); i++) { 300 int offset = static_cast<int>(i * sizeof(Smi*)); 301 FieldAccess access = {kUntaggedBase, 302 offset, 303 Handle<Name>(), 304 Type::Integral32(), 305 MachineType::AnyTagged(), 306 kNoWriteBarrier}; 307 308 SimplifiedLoweringTester<Object*> t; 309 Node* load = t.LoadField(access, t.PointerConstant(smis)); 310 t.Return(load); 311 t.LowerAllNodesAndLowerChanges(); 312 313 for (int j = -5; j <= 5; j++) { 314 Smi* expected = Smi::FromInt(j); 315 smis[i] = expected; 316 CHECK_EQ(expected, t.Call()); 317 } 318 } 319 } 320 321 322 TEST(RunStoreFieldToUntaggedBase) { 323 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)}; 324 325 for (size_t i = 0; i < arraysize(smis); i++) { 326 int offset = static_cast<int>(i * sizeof(Smi*)); 327 FieldAccess access = {kUntaggedBase, 328 offset, 329 Handle<Name>(), 330 Type::Integral32(), 331 MachineType::AnyTagged(), 332 kNoWriteBarrier}; 333 334 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 335 Node* p0 = t.Parameter(0); 336 t.StoreField(access, t.PointerConstant(smis), p0); 337 t.Return(p0); 338 t.LowerAllNodesAndLowerChanges(); 339 340 for (int j = -5; j <= 5; j++) { 341 Smi* expected = Smi::FromInt(j); 342 smis[i] = Smi::FromInt(-100); 343 CHECK_EQ(expected, t.Call(expected)); 344 CHECK_EQ(expected, smis[i]); 345 } 346 } 347 } 348 349 350 TEST(RunLoadElementFromUntaggedBase) { 351 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3), 352 Smi::FromInt(4), Smi::FromInt(5)}; 353 354 for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes 355 for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index 356 int offset = static_cast<int>(i * sizeof(Smi*)); 357 ElementAccess access = {kUntaggedBase, offset, Type::Integral32(), 358 MachineType::AnyTagged(), kNoWriteBarrier}; 359 360 SimplifiedLoweringTester<Object*> t; 361 Node* load = t.LoadElement(access, t.PointerConstant(smis), 362 t.Int32Constant(static_cast<int>(j))); 363 t.Return(load); 364 t.LowerAllNodesAndLowerChanges(); 365 366 for (int k = -5; k <= 5; k++) { 367 Smi* expected = Smi::FromInt(k); 368 smis[i + j] = expected; 369 CHECK_EQ(expected, t.Call()); 370 } 371 } 372 } 373 } 374 375 376 TEST(RunStoreElementFromUntaggedBase) { 377 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3), 378 Smi::FromInt(4), Smi::FromInt(5)}; 379 380 for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes 381 for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index 382 int offset = static_cast<int>(i * sizeof(Smi*)); 383 ElementAccess access = {kUntaggedBase, offset, Type::Integral32(), 384 MachineType::AnyTagged(), kNoWriteBarrier}; 385 386 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 387 Node* p0 = t.Parameter(0); 388 t.StoreElement(access, t.PointerConstant(smis), 389 t.Int32Constant(static_cast<int>(j)), p0); 390 t.Return(p0); 391 t.LowerAllNodesAndLowerChanges(); 392 393 for (int k = -5; k <= 5; k++) { 394 Smi* expected = Smi::FromInt(k); 395 smis[i + j] = Smi::FromInt(-100); 396 CHECK_EQ(expected, t.Call(expected)); 397 CHECK_EQ(expected, smis[i + j]); 398 } 399 400 // TODO(titzer): assert the contents of the array. 401 } 402 } 403 } 404 405 406 // A helper class for accessing fields and elements of various types, on both 407 // tagged and untagged base pointers. Contains both tagged and untagged buffers 408 // for testing direct memory access from generated code. 409 template <typename E> 410 class AccessTester : public HandleAndZoneScope { 411 public: 412 bool tagged; 413 MachineType rep; 414 E* original_elements; 415 size_t num_elements; 416 E* untagged_array; 417 Handle<ByteArray> tagged_array; // TODO(titzer): use FixedArray for tagged. 418 419 AccessTester(bool t, MachineType r, E* orig, size_t num) 420 : tagged(t), 421 rep(r), 422 original_elements(orig), 423 num_elements(num), 424 untagged_array(static_cast<E*>(malloc(ByteSize()))), 425 tagged_array(main_isolate()->factory()->NewByteArray( 426 static_cast<int>(ByteSize()))) { 427 Reinitialize(); 428 } 429 430 ~AccessTester() { free(untagged_array); } 431 432 size_t ByteSize() { return num_elements * sizeof(E); } 433 434 // Nuke both {untagged_array} and {tagged_array} with {original_elements}. 435 void Reinitialize() { 436 memcpy(untagged_array, original_elements, ByteSize()); 437 CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length()); 438 E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress()); 439 memcpy(raw, original_elements, ByteSize()); 440 } 441 442 // Create and run code that copies the element in either {untagged_array} 443 // or {tagged_array} at index {from_index} to index {to_index}. 444 void RunCopyElement(int from_index, int to_index) { 445 // TODO(titzer): test element and field accesses where the base is not 446 // a constant in the code. 447 BoundsCheck(from_index); 448 BoundsCheck(to_index); 449 ElementAccess access = GetElementAccess(); 450 451 SimplifiedLoweringTester<Object*> t; 452 Node* ptr = GetBaseNode(&t); 453 Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index)); 454 t.StoreElement(access, ptr, t.Int32Constant(to_index), load); 455 t.Return(t.jsgraph.TrueConstant()); 456 t.LowerAllNodesAndLowerChanges(); 457 t.GenerateCode(); 458 459 Object* result = t.Call(); 460 CHECK_EQ(t.isolate()->heap()->true_value(), result); 461 } 462 463 // Create and run code that copies the field in either {untagged_array} 464 // or {tagged_array} at index {from_index} to index {to_index}. 465 void RunCopyField(int from_index, int to_index) { 466 BoundsCheck(from_index); 467 BoundsCheck(to_index); 468 FieldAccess from_access = GetFieldAccess(from_index); 469 FieldAccess to_access = GetFieldAccess(to_index); 470 471 SimplifiedLoweringTester<Object*> t; 472 Node* ptr = GetBaseNode(&t); 473 Node* load = t.LoadField(from_access, ptr); 474 t.StoreField(to_access, ptr, load); 475 t.Return(t.jsgraph.TrueConstant()); 476 t.LowerAllNodesAndLowerChanges(); 477 t.GenerateCode(); 478 479 Object* result = t.Call(); 480 CHECK_EQ(t.isolate()->heap()->true_value(), result); 481 } 482 483 // Create and run code that copies the elements from {this} to {that}. 484 void RunCopyElements(AccessTester<E>* that) { 485 // TODO(titzer): Rewrite this test without StructuredGraphBuilder support. 486 #if 0 487 SimplifiedLoweringTester<Object*> t; 488 489 Node* one = t.Int32Constant(1); 490 Node* index = t.Int32Constant(0); 491 Node* limit = t.Int32Constant(static_cast<int>(num_elements)); 492 t.environment()->Push(index); 493 Node* src = this->GetBaseNode(&t); 494 Node* dst = that->GetBaseNode(&t); 495 { 496 LoopBuilder loop(&t); 497 loop.BeginLoop(); 498 // Loop exit condition 499 index = t.environment()->Top(); 500 Node* condition = t.Int32LessThan(index, limit); 501 loop.BreakUnless(condition); 502 // dst[index] = src[index] 503 index = t.environment()->Pop(); 504 Node* load = t.LoadElement(this->GetElementAccess(), src, index); 505 t.StoreElement(that->GetElementAccess(), dst, index, load); 506 // index++ 507 index = t.Int32Add(index, one); 508 t.environment()->Push(index); 509 // continue 510 loop.EndBody(); 511 loop.EndLoop(); 512 } 513 index = t.environment()->Pop(); 514 t.Return(t.jsgraph.TrueConstant()); 515 t.LowerAllNodes(); 516 t.GenerateCode(); 517 518 Object* result = t.Call(); 519 CHECK_EQ(t.isolate()->heap()->true_value(), result); 520 #endif 521 } 522 523 E GetElement(int index) { 524 BoundsCheck(index); 525 if (tagged) { 526 return GetTaggedElement(index); 527 } else { 528 return untagged_array[index]; 529 } 530 } 531 532 private: 533 ElementAccess GetElementAccess() { 534 ElementAccess access = {tagged ? kTaggedBase : kUntaggedBase, 535 tagged ? FixedArrayBase::kHeaderSize : 0, 536 Type::Any(), rep, kFullWriteBarrier}; 537 return access; 538 } 539 540 FieldAccess GetFieldAccess(int field) { 541 int offset = field * sizeof(E); 542 FieldAccess access = {tagged ? kTaggedBase : kUntaggedBase, 543 offset + (tagged ? FixedArrayBase::kHeaderSize : 0), 544 Handle<Name>(), 545 Type::Any(), 546 rep, 547 kFullWriteBarrier}; 548 return access; 549 } 550 551 template <typename T> 552 Node* GetBaseNode(SimplifiedLoweringTester<T>* t) { 553 return tagged ? t->HeapConstant(tagged_array) 554 : t->PointerConstant(untagged_array); 555 } 556 557 void BoundsCheck(int index) { 558 CHECK_GE(index, 0); 559 CHECK_LT(index, static_cast<int>(num_elements)); 560 CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length()); 561 } 562 563 E GetTaggedElement(int index) { 564 E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress()); 565 return raw[index]; 566 } 567 }; 568 569 template <> 570 double AccessTester<double>::GetTaggedElement(int index) { 571 return ReadDoubleValue(tagged_array->GetDataStartAddress() + 572 index * sizeof(double)); 573 } 574 575 576 template <typename E> 577 static void RunAccessTest(MachineType rep, E* original_elements, size_t num) { 578 int num_elements = static_cast<int>(num); 579 580 for (int taggedness = 0; taggedness < 2; taggedness++) { 581 AccessTester<E> a(taggedness == 1, rep, original_elements, num); 582 for (int field = 0; field < 2; field++) { 583 for (int i = 0; i < num_elements - 1; i++) { 584 a.Reinitialize(); 585 if (field == 0) { 586 a.RunCopyField(i, i + 1); // Test field read/write. 587 } else { 588 a.RunCopyElement(i, i + 1); // Test element read/write. 589 } 590 for (int j = 0; j < num_elements; j++) { 591 E expect = 592 j == (i + 1) ? original_elements[i] : original_elements[j]; 593 CHECK_EQ(expect, a.GetElement(j)); 594 } 595 } 596 } 597 } 598 // Test array copy. 599 for (int tf = 0; tf < 2; tf++) { 600 for (int tt = 0; tt < 2; tt++) { 601 AccessTester<E> a(tf == 1, rep, original_elements, num); 602 AccessTester<E> b(tt == 1, rep, original_elements, num); 603 a.RunCopyElements(&b); 604 for (int i = 0; i < num_elements; i++) { 605 CHECK_EQ(a.GetElement(i), b.GetElement(i)); 606 } 607 } 608 } 609 } 610 611 612 TEST(RunAccessTests_uint8) { 613 uint8_t data[] = {0x07, 0x16, 0x25, 0x34, 0x43, 0x99, 614 0xab, 0x78, 0x89, 0x19, 0x2b, 0x38}; 615 RunAccessTest<uint8_t>(MachineType::Int8(), data, arraysize(data)); 616 } 617 618 619 TEST(RunAccessTests_uint16) { 620 uint16_t data[] = {0x071a, 0x162b, 0x253c, 0x344d, 0x435e, 0x7777}; 621 RunAccessTest<uint16_t>(MachineType::Int16(), data, arraysize(data)); 622 } 623 624 625 TEST(RunAccessTests_int32) { 626 int32_t data[] = {-211, 211, 628347, 2000000000, -2000000000, -1, -100000034}; 627 RunAccessTest<int32_t>(MachineType::Int32(), data, arraysize(data)); 628 } 629 630 631 #define V8_2PART_INT64(a, b) (((static_cast<int64_t>(a) << 32) + 0x##b##u)) 632 633 634 TEST(RunAccessTests_int64) { 635 if (kPointerSize != 8) return; 636 int64_t data[] = {V8_2PART_INT64(0x10111213, 14151617), 637 V8_2PART_INT64(0x20212223, 24252627), 638 V8_2PART_INT64(0x30313233, 34353637), 639 V8_2PART_INT64(0xa0a1a2a3, a4a5a6a7), 640 V8_2PART_INT64(0xf0f1f2f3, f4f5f6f7)}; 641 RunAccessTest<int64_t>(MachineType::Int64(), data, arraysize(data)); 642 } 643 644 645 TEST(RunAccessTests_float64) { 646 double data[] = {1.25, -1.25, 2.75, 11.0, 11100.8}; 647 RunAccessTest<double>(MachineType::Float64(), data, arraysize(data)); 648 } 649 650 651 TEST(RunAccessTests_Smi) { 652 Smi* data[] = {Smi::FromInt(-1), Smi::FromInt(-9), 653 Smi::FromInt(0), Smi::FromInt(666), 654 Smi::FromInt(77777), Smi::FromInt(Smi::kMaxValue)}; 655 RunAccessTest<Smi*>(MachineType::AnyTagged(), data, arraysize(data)); 656 } 657 658 659 TEST(RunAllocate) { 660 PretenureFlag flag[] = {NOT_TENURED, TENURED}; 661 662 for (size_t i = 0; i < arraysize(flag); i++) { 663 SimplifiedLoweringTester<HeapObject*> t; 664 FieldAccess access = AccessBuilder::ForMap(); 665 Node* size = t.jsgraph.Constant(HeapNumber::kSize); 666 Node* alloc = t.NewNode(t.simplified()->Allocate(flag[i]), size); 667 Node* map = t.jsgraph.Constant(t.factory()->heap_number_map()); 668 t.StoreField(access, alloc, map); 669 t.Return(alloc); 670 671 t.LowerAllNodesAndLowerChanges(); 672 t.GenerateCode(); 673 674 HeapObject* result = t.CallWithPotentialGC<HeapObject>(); 675 CHECK(t.heap()->new_space()->Contains(result) || flag[i] == TENURED); 676 CHECK(t.heap()->old_space()->Contains(result) || flag[i] == NOT_TENURED); 677 CHECK(result->IsHeapNumber()); 678 } 679 } 680 681 682 // Fills in most of the nodes of the graph in order to make tests shorter. 683 class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders { 684 public: 685 Typer typer; 686 JSOperatorBuilder javascript; 687 JSGraph jsgraph; 688 Node* p0; 689 Node* p1; 690 Node* p2; 691 Node* start; 692 Node* end; 693 Node* ret; 694 695 explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(), 696 Type* p2_type = Type::None()) 697 : GraphAndBuilders(main_zone()), 698 typer(main_isolate(), graph()), 699 javascript(main_zone()), 700 jsgraph(main_isolate(), graph(), common(), &javascript, simplified(), 701 machine()) { 702 start = graph()->NewNode(common()->Start(4)); 703 graph()->SetStart(start); 704 ret = 705 graph()->NewNode(common()->Return(), jsgraph.Constant(0), start, start); 706 end = graph()->NewNode(common()->End(1), ret); 707 graph()->SetEnd(end); 708 p0 = graph()->NewNode(common()->Parameter(0), start); 709 p1 = graph()->NewNode(common()->Parameter(1), start); 710 p2 = graph()->NewNode(common()->Parameter(2), start); 711 typer.Run(); 712 NodeProperties::SetType(p0, p0_type); 713 NodeProperties::SetType(p1, p1_type); 714 NodeProperties::SetType(p2, p2_type); 715 } 716 717 void CheckLoweringBinop(IrOpcode::Value expected, const Operator* op) { 718 Node* node = Return(graph()->NewNode(op, p0, p1)); 719 Lower(); 720 CHECK_EQ(expected, node->opcode()); 721 } 722 723 void CheckLoweringStringBinop(IrOpcode::Value expected, const Operator* op) { 724 Node* node = Return( 725 graph()->NewNode(op, p0, p1, graph()->start(), graph()->start())); 726 Lower(); 727 CHECK_EQ(expected, node->opcode()); 728 } 729 730 void CheckLoweringTruncatedBinop(IrOpcode::Value expected, const Operator* op, 731 const Operator* trunc) { 732 Node* node = graph()->NewNode(op, p0, p1); 733 Return(graph()->NewNode(trunc, node)); 734 Lower(); 735 CHECK_EQ(expected, node->opcode()); 736 } 737 738 void Lower() { 739 SourcePositionTable table(jsgraph.graph()); 740 SimplifiedLowering(&jsgraph, jsgraph.zone(), &table).LowerAllNodes(); 741 } 742 743 void LowerAllNodesAndLowerChanges() { 744 SourcePositionTable table(jsgraph.graph()); 745 SimplifiedLowering(&jsgraph, jsgraph.zone(), &table).LowerAllNodes(); 746 747 Schedule* schedule = Scheduler::ComputeSchedule(this->zone(), this->graph(), 748 Scheduler::kNoFlags); 749 EffectControlLinearizer linearizer(&jsgraph, schedule, this->zone()); 750 linearizer.Run(); 751 752 MemoryOptimizer memory_optimizer(&jsgraph, this->zone()); 753 memory_optimizer.Optimize(); 754 } 755 756 // Inserts the node as the return value of the graph. 757 Node* Return(Node* node) { 758 ret->ReplaceInput(0, node); 759 return node; 760 } 761 762 // Inserts the node as the effect input to the return of the graph. 763 void Effect(Node* node) { ret->ReplaceInput(1, node); } 764 765 Node* ExampleWithOutput(MachineType type) { 766 if (type.semantic() == MachineSemantic::kInt32) { 767 return graph()->NewNode(machine()->Int32Add(), jsgraph.Int32Constant(1), 768 jsgraph.Int32Constant(1)); 769 } else if (type.semantic() == MachineSemantic::kUint32) { 770 return graph()->NewNode(machine()->Word32Shr(), jsgraph.Int32Constant(1), 771 jsgraph.Int32Constant(1)); 772 } else if (type.representation() == MachineRepresentation::kFloat64) { 773 return graph()->NewNode(machine()->Float64Add(), 774 jsgraph.Float64Constant(1), 775 jsgraph.Float64Constant(1)); 776 } else if (type.representation() == MachineRepresentation::kBit) { 777 return graph()->NewNode(machine()->Word32Equal(), 778 jsgraph.Int32Constant(1), 779 jsgraph.Int32Constant(1)); 780 } else if (type.representation() == MachineRepresentation::kWord64) { 781 return graph()->NewNode(machine()->Int64Add(), Int64Constant(1), 782 Int64Constant(1)); 783 } else { 784 CHECK(type.representation() == MachineRepresentation::kTagged); 785 return p0; 786 } 787 } 788 789 Node* Use(Node* node, MachineType type) { 790 if (type.semantic() == MachineSemantic::kInt32) { 791 return graph()->NewNode(machine()->Int32LessThan(), node, 792 jsgraph.Int32Constant(1)); 793 } else if (type.semantic() == MachineSemantic::kUint32) { 794 return graph()->NewNode(machine()->Uint32LessThan(), node, 795 jsgraph.Int32Constant(1)); 796 } else if (type.representation() == MachineRepresentation::kFloat64) { 797 return graph()->NewNode(machine()->Float64Add(), node, 798 jsgraph.Float64Constant(1)); 799 } else if (type.representation() == MachineRepresentation::kWord64) { 800 return graph()->NewNode(machine()->Int64LessThan(), node, 801 Int64Constant(1)); 802 } else if (type.representation() == MachineRepresentation::kWord32) { 803 return graph()->NewNode(machine()->Word32Equal(), node, 804 jsgraph.Int32Constant(1)); 805 } else { 806 return graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), node, 807 jsgraph.TrueConstant()); 808 } 809 } 810 811 Node* Branch(Node* cond) { 812 Node* br = graph()->NewNode(common()->Branch(), cond, start); 813 Node* tb = graph()->NewNode(common()->IfTrue(), br); 814 Node* fb = graph()->NewNode(common()->IfFalse(), br); 815 Node* m = graph()->NewNode(common()->Merge(2), tb, fb); 816 NodeProperties::ReplaceControlInput(ret, m); 817 return br; 818 } 819 820 Node* Int64Constant(int64_t v) { 821 return graph()->NewNode(common()->Int64Constant(v)); 822 } 823 824 SimplifiedOperatorBuilder* simplified() { return &main_simplified_; } 825 MachineOperatorBuilder* machine() { return &main_machine_; } 826 CommonOperatorBuilder* common() { return &main_common_; } 827 Graph* graph() { return main_graph_; } 828 }; 829 830 831 TEST(LowerBooleanNot_bit_bit) { 832 // BooleanNot(x: kRepBit) used as kRepBit 833 TestingGraph t(Type::Boolean()); 834 Node* b = t.ExampleWithOutput(MachineType::Bool()); 835 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b); 836 Node* use = t.Branch(inv); 837 t.Lower(); 838 Node* cmp = use->InputAt(0); 839 CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode()); 840 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1)); 841 Node* f = t.jsgraph.Int32Constant(0); 842 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1)); 843 } 844 845 846 TEST(LowerBooleanNot_bit_tagged) { 847 // BooleanNot(x: kRepBit) used as kRepTagged 848 TestingGraph t(Type::Boolean()); 849 Node* b = t.ExampleWithOutput(MachineType::Bool()); 850 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b); 851 Node* use = t.Use(inv, MachineType::AnyTagged()); 852 t.Return(use); 853 t.Lower(); 854 CHECK_EQ(IrOpcode::kChangeBitToTagged, use->InputAt(0)->opcode()); 855 Node* cmp = use->InputAt(0)->InputAt(0); 856 CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode()); 857 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1)); 858 Node* f = t.jsgraph.Int32Constant(0); 859 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1)); 860 } 861 862 863 TEST(LowerBooleanNot_tagged_bit) { 864 // BooleanNot(x: kRepTagged) used as kRepBit 865 TestingGraph t(Type::Boolean()); 866 Node* b = t.p0; 867 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b); 868 Node* use = t.Branch(inv); 869 t.Lower(); 870 Node* cmp = use->InputAt(0); 871 CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode()); 872 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1)); 873 Node* f = t.jsgraph.FalseConstant(); 874 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1)); 875 } 876 877 878 TEST(LowerBooleanNot_tagged_tagged) { 879 // BooleanNot(x: kRepTagged) used as kRepTagged 880 TestingGraph t(Type::Boolean()); 881 Node* b = t.p0; 882 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b); 883 Node* use = t.Use(inv, MachineType::AnyTagged()); 884 t.Return(use); 885 t.Lower(); 886 CHECK_EQ(IrOpcode::kChangeBitToTagged, use->InputAt(0)->opcode()); 887 Node* cmp = use->InputAt(0)->InputAt(0); 888 CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode()); 889 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1)); 890 Node* f = t.jsgraph.FalseConstant(); 891 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1)); 892 } 893 894 895 TEST(LowerBooleanToNumber_bit_int32) { 896 // BooleanToNumber(x: kRepBit) used as MachineType::Int32() 897 TestingGraph t(Type::Boolean()); 898 Node* b = t.ExampleWithOutput(MachineType::Bool()); 899 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b); 900 Node* use = t.Use(cnv, MachineType::Int32()); 901 t.Return(use); 902 t.Lower(); 903 CHECK_EQ(b, use->InputAt(0)); 904 } 905 906 907 TEST(LowerBooleanToNumber_tagged_int32) { 908 // BooleanToNumber(x: kRepTagged) used as MachineType::Int32() 909 TestingGraph t(Type::Boolean()); 910 Node* b = t.p0; 911 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b); 912 Node* use = t.Use(cnv, MachineType::Int32()); 913 t.Return(use); 914 t.Lower(); 915 CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode()); 916 CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1)); 917 Node* c = t.jsgraph.TrueConstant(); 918 CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1)); 919 } 920 921 922 TEST(LowerBooleanToNumber_bit_tagged) { 923 // BooleanToNumber(x: kRepBit) used as MachineType::AnyTagged() 924 TestingGraph t(Type::Boolean()); 925 Node* b = t.ExampleWithOutput(MachineType::Bool()); 926 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b); 927 Node* use = t.Use(cnv, MachineType::AnyTagged()); 928 t.Return(use); 929 t.Lower(); 930 CHECK_EQ(b, use->InputAt(0)->InputAt(0)); 931 CHECK_EQ(IrOpcode::kChangeInt31ToTaggedSigned, use->InputAt(0)->opcode()); 932 } 933 934 935 TEST(LowerBooleanToNumber_tagged_tagged) { 936 // BooleanToNumber(x: kRepTagged) used as MachineType::AnyTagged() 937 TestingGraph t(Type::Boolean()); 938 Node* b = t.p0; 939 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b); 940 Node* use = t.Use(cnv, MachineType::AnyTagged()); 941 t.Return(use); 942 t.Lower(); 943 CHECK_EQ(cnv, use->InputAt(0)->InputAt(0)); 944 CHECK_EQ(IrOpcode::kChangeInt31ToTaggedSigned, use->InputAt(0)->opcode()); 945 CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode()); 946 CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1)); 947 Node* c = t.jsgraph.TrueConstant(); 948 CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1)); 949 } 950 951 static Type* test_types[] = {Type::Signed32(), Type::Unsigned32(), 952 Type::Number()}; 953 954 TEST(LowerNumberCmp_to_int32) { 955 TestingGraph t(Type::Signed32(), Type::Signed32()); 956 957 t.CheckLoweringBinop(IrOpcode::kWord32Equal, t.simplified()->NumberEqual()); 958 t.CheckLoweringBinop(IrOpcode::kInt32LessThan, 959 t.simplified()->NumberLessThan()); 960 t.CheckLoweringBinop(IrOpcode::kInt32LessThanOrEqual, 961 t.simplified()->NumberLessThanOrEqual()); 962 } 963 964 965 TEST(LowerNumberCmp_to_uint32) { 966 TestingGraph t(Type::Unsigned32(), Type::Unsigned32()); 967 968 t.CheckLoweringBinop(IrOpcode::kWord32Equal, t.simplified()->NumberEqual()); 969 t.CheckLoweringBinop(IrOpcode::kUint32LessThan, 970 t.simplified()->NumberLessThan()); 971 t.CheckLoweringBinop(IrOpcode::kUint32LessThanOrEqual, 972 t.simplified()->NumberLessThanOrEqual()); 973 } 974 975 976 TEST(LowerNumberCmp_to_float64) { 977 TestingGraph t(Type::Number(), Type::Number()); 978 979 t.CheckLoweringBinop(IrOpcode::kFloat64Equal, t.simplified()->NumberEqual()); 980 t.CheckLoweringBinop(IrOpcode::kFloat64LessThan, 981 t.simplified()->NumberLessThan()); 982 t.CheckLoweringBinop(IrOpcode::kFloat64LessThanOrEqual, 983 t.simplified()->NumberLessThanOrEqual()); 984 } 985 986 987 TEST(LowerNumberAddSub_to_int32) { 988 HandleAndZoneScope scope; 989 Type* small_range = Type::Range(1, 10, scope.main_zone()); 990 Type* large_range = Type::Range(-1e+13, 1e+14, scope.main_zone()); 991 static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range, 992 large_range}; 993 994 for (size_t i = 0; i < arraysize(types); i++) { 995 for (size_t j = 0; j < arraysize(types); j++) { 996 TestingGraph t(types[i], types[j]); 997 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add, 998 t.simplified()->NumberAdd(), 999 t.simplified()->NumberToInt32()); 1000 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub, 1001 t.simplified()->NumberSubtract(), 1002 t.simplified()->NumberToInt32()); 1003 } 1004 } 1005 } 1006 1007 1008 TEST(LowerNumberAddSub_to_uint32) { 1009 HandleAndZoneScope scope; 1010 Type* small_range = Type::Range(1, 10, scope.main_zone()); 1011 Type* large_range = Type::Range(-1e+13, 1e+14, scope.main_zone()); 1012 static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range, 1013 large_range}; 1014 1015 for (size_t i = 0; i < arraysize(types); i++) { 1016 for (size_t j = 0; j < arraysize(types); j++) { 1017 TestingGraph t(types[i], types[j]); 1018 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add, 1019 t.simplified()->NumberAdd(), 1020 t.simplified()->NumberToUint32()); 1021 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub, 1022 t.simplified()->NumberSubtract(), 1023 t.simplified()->NumberToUint32()); 1024 } 1025 } 1026 } 1027 1028 1029 TEST(LowerNumberAddSub_to_float64) { 1030 for (size_t i = 0; i < arraysize(test_types); i++) { 1031 TestingGraph t(test_types[i], test_types[i]); 1032 1033 t.CheckLoweringBinop(IrOpcode::kFloat64Add, t.simplified()->NumberAdd()); 1034 t.CheckLoweringBinop(IrOpcode::kFloat64Sub, 1035 t.simplified()->NumberSubtract()); 1036 } 1037 } 1038 1039 1040 TEST(LowerNumberDivMod_to_float64) { 1041 for (size_t i = 0; i < arraysize(test_types); i++) { 1042 TestingGraph t(test_types[i], test_types[i]); 1043 1044 t.CheckLoweringBinop(IrOpcode::kFloat64Div, t.simplified()->NumberDivide()); 1045 if (!test_types[i]->Is(Type::Unsigned32())) { 1046 t.CheckLoweringBinop(IrOpcode::kFloat64Mod, 1047 t.simplified()->NumberModulus()); 1048 } 1049 } 1050 } 1051 1052 1053 static void CheckChangeOf(IrOpcode::Value change, Node* of, Node* node) { 1054 CHECK_EQ(change, node->opcode()); 1055 CHECK_EQ(of, node->InputAt(0)); 1056 } 1057 1058 1059 TEST(LowerNumberToInt32_to_ChangeTaggedToInt32) { 1060 // NumberToInt32(x: kRepTagged | kTypeInt32) used as kRepWord32 1061 TestingGraph t(Type::Signed32()); 1062 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0); 1063 Node* use = t.Use(trunc, MachineType::Int32()); 1064 t.Return(use); 1065 t.Lower(); 1066 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p0, use->InputAt(0)); 1067 } 1068 1069 TEST(LowerNumberToInt32_to_TruncateFloat64ToWord32) { 1070 // NumberToInt32(x: kRepFloat64) used as MachineType::Int32() 1071 TestingGraph t(Type::Number()); 1072 Node* p0 = t.ExampleWithOutput(MachineType::Float64()); 1073 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), p0); 1074 Node* use = t.Use(trunc, MachineType::Int32()); 1075 t.Return(use); 1076 t.Lower(); 1077 CheckChangeOf(IrOpcode::kTruncateFloat64ToWord32, p0, use->InputAt(0)); 1078 } 1079 1080 TEST(LowerNumberToInt32_to_TruncateTaggedToWord32) { 1081 // NumberToInt32(x: kTypeNumber | kRepTagged) used as MachineType::Int32() 1082 TestingGraph t(Type::Number()); 1083 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0); 1084 Node* use = t.Use(trunc, MachineType::Int32()); 1085 t.Return(use); 1086 t.Lower(); 1087 CheckChangeOf(IrOpcode::kTruncateTaggedToWord32, t.p0, use->InputAt(0)); 1088 } 1089 1090 1091 TEST(LowerNumberToUint32_to_ChangeTaggedToUint32) { 1092 // NumberToUint32(x: kRepTagged | kTypeUint32) used as kRepWord32 1093 TestingGraph t(Type::Unsigned32()); 1094 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0); 1095 Node* use = t.Use(trunc, MachineType::Uint32()); 1096 t.Return(use); 1097 t.Lower(); 1098 CheckChangeOf(IrOpcode::kChangeTaggedToUint32, t.p0, use->InputAt(0)); 1099 } 1100 1101 TEST(LowerNumberToUint32_to_TruncateFloat64ToWord32) { 1102 // NumberToUint32(x: kRepFloat64) used as MachineType::Uint32() 1103 TestingGraph t(Type::Number()); 1104 Node* p0 = t.ExampleWithOutput(MachineType::Float64()); 1105 // TODO(titzer): run the typer here, or attach machine type to param. 1106 NodeProperties::SetType(p0, Type::Number()); 1107 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), p0); 1108 Node* use = t.Use(trunc, MachineType::Uint32()); 1109 t.Return(use); 1110 t.Lower(); 1111 CheckChangeOf(IrOpcode::kTruncateFloat64ToWord32, p0, use->InputAt(0)); 1112 } 1113 1114 TEST(LowerNumberToUint32_to_TruncateTaggedToWord32) { 1115 // NumberToInt32(x: kTypeNumber | kRepTagged) used as MachineType::Uint32() 1116 TestingGraph t(Type::Number()); 1117 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0); 1118 Node* use = t.Use(trunc, MachineType::Uint32()); 1119 t.Return(use); 1120 t.Lower(); 1121 CheckChangeOf(IrOpcode::kTruncateTaggedToWord32, t.p0, use->InputAt(0)); 1122 } 1123 1124 TEST(LowerNumberToUint32_to_TruncateFloat64ToWord32_uint32) { 1125 // NumberToUint32(x: kRepFloat64) used as kRepWord32 1126 TestingGraph t(Type::Unsigned32()); 1127 Node* input = t.ExampleWithOutput(MachineType::Float64()); 1128 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), input); 1129 Node* use = t.Use(trunc, MachineType::RepWord32()); 1130 t.Return(use); 1131 t.Lower(); 1132 CheckChangeOf(IrOpcode::kTruncateFloat64ToWord32, input, use->InputAt(0)); 1133 } 1134 1135 1136 TEST(LowerReferenceEqual_to_wordeq) { 1137 TestingGraph t(Type::Any(), Type::Any()); 1138 IrOpcode::Value opcode = 1139 static_cast<IrOpcode::Value>(t.machine()->WordEqual()->opcode()); 1140 t.CheckLoweringBinop(opcode, t.simplified()->ReferenceEqual(Type::Any())); 1141 } 1142 1143 void CheckChangeInsertion(IrOpcode::Value expected, MachineType from, 1144 MachineType to, Type* type = Type::Any()) { 1145 TestingGraph t(Type::Any()); 1146 Node* in = t.ExampleWithOutput(from); 1147 NodeProperties::SetType(in, type); 1148 Node* use = t.Use(in, to); 1149 t.Return(use); 1150 t.Lower(); 1151 CHECK_EQ(expected, use->InputAt(0)->opcode()); 1152 CHECK_EQ(in, use->InputAt(0)->InputAt(0)); 1153 } 1154 1155 TEST(InsertBasicChanges) { 1156 CheckChangeInsertion(IrOpcode::kChangeFloat64ToInt32, MachineType::Float64(), 1157 MachineType::Int32(), Type::Signed32()); 1158 CheckChangeInsertion(IrOpcode::kChangeFloat64ToUint32, MachineType::Float64(), 1159 MachineType::Uint32(), Type::Unsigned32()); 1160 CheckChangeInsertion(IrOpcode::kTruncateFloat64ToWord32, 1161 MachineType::Float64(), MachineType::Uint32(), 1162 Type::Integral32()); 1163 CheckChangeInsertion(IrOpcode::kChangeTaggedToInt32, MachineType::AnyTagged(), 1164 MachineType::Int32(), Type::Signed32()); 1165 CheckChangeInsertion(IrOpcode::kChangeTaggedToUint32, 1166 MachineType::AnyTagged(), MachineType::Uint32(), 1167 Type::Unsigned32()); 1168 1169 CheckChangeInsertion(IrOpcode::kChangeFloat64ToTagged, MachineType::Float64(), 1170 MachineType::AnyTagged(), Type::Number()); 1171 CheckChangeInsertion(IrOpcode::kChangeTaggedToFloat64, 1172 MachineType::AnyTagged(), MachineType::Float64(), 1173 Type::Number()); 1174 1175 CheckChangeInsertion(IrOpcode::kChangeInt32ToFloat64, MachineType::Int32(), 1176 MachineType::Float64(), Type::Signed32()); 1177 CheckChangeInsertion(IrOpcode::kChangeInt32ToTagged, MachineType::Int32(), 1178 MachineType::AnyTagged(), Type::Signed32()); 1179 1180 CheckChangeInsertion(IrOpcode::kChangeUint32ToFloat64, MachineType::Uint32(), 1181 MachineType::Float64(), Type::Unsigned32()); 1182 CheckChangeInsertion(IrOpcode::kChangeUint32ToTagged, MachineType::Uint32(), 1183 MachineType::AnyTagged(), Type::Unsigned32()); 1184 } 1185 1186 static void CheckChangesAroundBinop(TestingGraph* t, const Operator* op, 1187 IrOpcode::Value input_change, 1188 IrOpcode::Value output_change, 1189 Type* type = Type::Any()) { 1190 Node* binop = 1191 op->ControlInputCount() == 0 1192 ? t->graph()->NewNode(op, t->p0, t->p1) 1193 : t->graph()->NewNode(op, t->p0, t->p1, t->graph()->start()); 1194 NodeProperties::SetType(binop, type); 1195 t->Return(binop); 1196 t->Lower(); 1197 CHECK_EQ(input_change, binop->InputAt(0)->opcode()); 1198 CHECK_EQ(input_change, binop->InputAt(1)->opcode()); 1199 CHECK_EQ(t->p0, binop->InputAt(0)->InputAt(0)); 1200 CHECK_EQ(t->p1, binop->InputAt(1)->InputAt(0)); 1201 CHECK_EQ(output_change, t->ret->InputAt(0)->opcode()); 1202 CHECK_EQ(binop, t->ret->InputAt(0)->InputAt(0)); 1203 } 1204 1205 1206 TEST(InsertChangesAroundInt32Binops) { 1207 TestingGraph t(Type::Signed32(), Type::Signed32()); 1208 1209 const Operator* ops[] = {t.machine()->Int32Add(), t.machine()->Int32Sub(), 1210 t.machine()->Int32Mul(), t.machine()->Int32Div(), 1211 t.machine()->Int32Mod(), t.machine()->Word32And(), 1212 t.machine()->Word32Or(), t.machine()->Word32Xor(), 1213 t.machine()->Word32Shl(), t.machine()->Word32Sar()}; 1214 1215 for (size_t i = 0; i < arraysize(ops); i++) { 1216 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32, 1217 IrOpcode::kChangeInt32ToTagged, Type::Signed32()); 1218 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32, 1219 IrOpcode::kChangeInt32ToTagged, Type::Signed32()); 1220 } 1221 } 1222 1223 1224 TEST(InsertChangesAroundInt32Cmp) { 1225 TestingGraph t(Type::Signed32(), Type::Signed32()); 1226 1227 const Operator* ops[] = {t.machine()->Int32LessThan(), 1228 t.machine()->Int32LessThanOrEqual()}; 1229 1230 for (size_t i = 0; i < arraysize(ops); i++) { 1231 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32, 1232 IrOpcode::kChangeBitToTagged); 1233 } 1234 } 1235 1236 1237 TEST(InsertChangesAroundUint32Cmp) { 1238 TestingGraph t(Type::Unsigned32(), Type::Unsigned32()); 1239 1240 const Operator* ops[] = {t.machine()->Uint32LessThan(), 1241 t.machine()->Uint32LessThanOrEqual()}; 1242 1243 for (size_t i = 0; i < arraysize(ops); i++) { 1244 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToUint32, 1245 IrOpcode::kChangeBitToTagged); 1246 } 1247 } 1248 1249 1250 TEST(InsertChangesAroundFloat64Binops) { 1251 TestingGraph t(Type::Number(), Type::Number()); 1252 1253 const Operator* ops[] = { 1254 t.machine()->Float64Add(), t.machine()->Float64Sub(), 1255 t.machine()->Float64Mul(), t.machine()->Float64Div(), 1256 t.machine()->Float64Mod(), 1257 }; 1258 1259 for (size_t i = 0; i < arraysize(ops); i++) { 1260 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToFloat64, 1261 IrOpcode::kChangeFloat64ToTagged, Type::Number()); 1262 } 1263 } 1264 1265 1266 TEST(InsertChangesAroundFloat64Cmp) { 1267 TestingGraph t(Type::Number(), Type::Number()); 1268 1269 const Operator* ops[] = {t.machine()->Float64Equal(), 1270 t.machine()->Float64LessThan(), 1271 t.machine()->Float64LessThanOrEqual()}; 1272 1273 for (size_t i = 0; i < arraysize(ops); i++) { 1274 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToFloat64, 1275 IrOpcode::kChangeBitToTagged); 1276 } 1277 } 1278 1279 1280 namespace { 1281 1282 void CheckFieldAccessArithmetic(FieldAccess access, Node* load_or_store) { 1283 IntPtrMatcher mindex(load_or_store->InputAt(1)); 1284 CHECK(mindex.Is(access.offset - access.tag())); 1285 } 1286 1287 1288 Node* CheckElementAccessArithmetic(ElementAccess access, Node* load_or_store) { 1289 Node* index = load_or_store->InputAt(1); 1290 if (kPointerSize == 8) { 1291 CHECK_EQ(IrOpcode::kChangeUint32ToUint64, index->opcode()); 1292 index = index->InputAt(0); 1293 } 1294 1295 Int32BinopMatcher mindex(index); 1296 CHECK_EQ(IrOpcode::kInt32Add, mindex.node()->opcode()); 1297 CHECK(mindex.right().Is(access.header_size - access.tag())); 1298 1299 const int element_size_shift = 1300 ElementSizeLog2Of(access.machine_type.representation()); 1301 if (element_size_shift) { 1302 Int32BinopMatcher shl(mindex.left().node()); 1303 CHECK_EQ(IrOpcode::kWord32Shl, shl.node()->opcode()); 1304 CHECK(shl.right().Is(element_size_shift)); 1305 return shl.left().node(); 1306 } else { 1307 return mindex.left().node(); 1308 } 1309 } 1310 1311 1312 const MachineType kMachineReps[] = { 1313 MachineType::Int8(), MachineType::Int16(), MachineType::Int32(), 1314 MachineType::Uint32(), MachineType::Int64(), MachineType::Float64(), 1315 MachineType::AnyTagged()}; 1316 1317 } // namespace 1318 1319 1320 TEST(LowerLoadField_to_load) { 1321 for (size_t i = 0; i < arraysize(kMachineReps); i++) { 1322 TestingGraph t(Type::Any(), Type::Signed32()); 1323 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, 1324 Handle<Name>::null(), Type::Any(), 1325 kMachineReps[i], kNoWriteBarrier}; 1326 1327 Node* load = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, 1328 t.start, t.start); 1329 Node* use = t.Use(load, kMachineReps[i]); 1330 t.Return(use); 1331 t.LowerAllNodesAndLowerChanges(); 1332 CHECK_EQ(IrOpcode::kLoad, load->opcode()); 1333 CHECK_EQ(t.p0, load->InputAt(0)); 1334 CheckFieldAccessArithmetic(access, load); 1335 1336 MachineType rep = LoadRepresentationOf(load->op()); 1337 CHECK_EQ(kMachineReps[i], rep); 1338 } 1339 } 1340 1341 1342 TEST(LowerStoreField_to_store) { 1343 { 1344 TestingGraph t(Type::Any(), Type::Signed32()); 1345 1346 for (size_t i = 0; i < arraysize(kMachineReps); i++) { 1347 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, 1348 Handle<Name>::null(), Type::Any(), 1349 kMachineReps[i], kNoWriteBarrier}; 1350 1351 Node* val = t.ExampleWithOutput(kMachineReps[i]); 1352 Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0, 1353 val, t.start, t.start); 1354 t.Effect(store); 1355 t.LowerAllNodesAndLowerChanges(); 1356 CHECK_EQ(IrOpcode::kStore, store->opcode()); 1357 CHECK_EQ(val, store->InputAt(2)); 1358 CheckFieldAccessArithmetic(access, store); 1359 1360 StoreRepresentation rep = StoreRepresentationOf(store->op()); 1361 if (kMachineReps[i].representation() == MachineRepresentation::kTagged) { 1362 CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind()); 1363 } 1364 CHECK_EQ(kMachineReps[i].representation(), rep.representation()); 1365 } 1366 } 1367 { 1368 HandleAndZoneScope scope; 1369 Zone* z = scope.main_zone(); 1370 TestingGraph t(Type::Any(), Type::Intersect(Type::SignedSmall(), 1371 Type::TaggedSigned(), z)); 1372 FieldAccess access = { 1373 kTaggedBase, FixedArrayBase::kHeaderSize, Handle<Name>::null(), 1374 Type::Any(), MachineType::AnyTagged(), kNoWriteBarrier}; 1375 Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0, 1376 t.p1, t.start, t.start); 1377 t.Effect(store); 1378 t.LowerAllNodesAndLowerChanges(); 1379 CHECK_EQ(IrOpcode::kStore, store->opcode()); 1380 CHECK_EQ(t.p1, store->InputAt(2)); 1381 StoreRepresentation rep = StoreRepresentationOf(store->op()); 1382 CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind()); 1383 } 1384 } 1385 1386 1387 TEST(LowerLoadElement_to_load) { 1388 for (size_t i = 0; i < arraysize(kMachineReps); i++) { 1389 TestingGraph t(Type::Any(), Type::Signed32()); 1390 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, 1391 Type::Any(), kMachineReps[i], kNoWriteBarrier}; 1392 1393 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, 1394 t.p1, t.start, t.start); 1395 Node* use = t.Use(load, kMachineReps[i]); 1396 t.Return(use); 1397 t.LowerAllNodesAndLowerChanges(); 1398 CHECK_EQ(IrOpcode::kLoad, load->opcode()); 1399 CHECK_EQ(t.p0, load->InputAt(0)); 1400 CheckElementAccessArithmetic(access, load); 1401 1402 MachineType rep = LoadRepresentationOf(load->op()); 1403 CHECK_EQ(kMachineReps[i], rep); 1404 } 1405 } 1406 1407 1408 TEST(LowerStoreElement_to_store) { 1409 { 1410 for (size_t i = 0; i < arraysize(kMachineReps); i++) { 1411 TestingGraph t(Type::Any(), Type::Signed32()); 1412 1413 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, 1414 Type::Any(), kMachineReps[i], kNoWriteBarrier}; 1415 1416 Node* val = t.ExampleWithOutput(kMachineReps[i]); 1417 Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), 1418 t.p0, t.p1, val, t.start, t.start); 1419 t.Effect(store); 1420 t.LowerAllNodesAndLowerChanges(); 1421 CHECK_EQ(IrOpcode::kStore, store->opcode()); 1422 CHECK_EQ(val, store->InputAt(2)); 1423 CheckElementAccessArithmetic(access, store); 1424 1425 StoreRepresentation rep = StoreRepresentationOf(store->op()); 1426 if (kMachineReps[i].representation() == MachineRepresentation::kTagged) { 1427 CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind()); 1428 } 1429 CHECK_EQ(kMachineReps[i].representation(), rep.representation()); 1430 } 1431 } 1432 { 1433 HandleAndZoneScope scope; 1434 Zone* z = scope.main_zone(); 1435 TestingGraph t( 1436 Type::Any(), Type::Signed32(), 1437 Type::Intersect(Type::SignedSmall(), Type::TaggedSigned(), z)); 1438 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, 1439 Type::Any(), MachineType::AnyTagged(), 1440 kNoWriteBarrier}; 1441 Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, 1442 t.p1, t.p2, t.start, t.start); 1443 t.Effect(store); 1444 t.LowerAllNodesAndLowerChanges(); 1445 CHECK_EQ(IrOpcode::kStore, store->opcode()); 1446 CHECK_EQ(t.p2, store->InputAt(2)); 1447 StoreRepresentation rep = StoreRepresentationOf(store->op()); 1448 CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind()); 1449 } 1450 } 1451 1452 1453 TEST(InsertChangeForLoadElementIndex) { 1454 // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) => 1455 // Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k)) 1456 TestingGraph t(Type::Any(), Type::Signed32()); 1457 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), 1458 MachineType::AnyTagged(), kNoWriteBarrier}; 1459 1460 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, 1461 t.p1, t.start, t.start); 1462 t.Return(load); 1463 t.Lower(); 1464 CHECK_EQ(IrOpcode::kLoadElement, load->opcode()); 1465 CHECK_EQ(t.p0, load->InputAt(0)); 1466 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, load->InputAt(1)); 1467 } 1468 1469 1470 TEST(InsertChangeForStoreElementIndex) { 1471 // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) => 1472 // Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val) 1473 TestingGraph t(Type::Any(), Type::Signed32()); 1474 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), 1475 MachineType::AnyTagged(), kFullWriteBarrier}; 1476 1477 Node* store = 1478 t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, 1479 t.jsgraph.TrueConstant(), t.start, t.start); 1480 t.Effect(store); 1481 t.Lower(); 1482 CHECK_EQ(IrOpcode::kStoreElement, store->opcode()); 1483 CHECK_EQ(t.p0, store->InputAt(0)); 1484 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, store->InputAt(1)); 1485 } 1486 1487 1488 TEST(InsertChangeForLoadElement) { 1489 // TODO(titzer): test all load/store representation change insertions. 1490 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any()); 1491 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, 1492 Type::Number(), MachineType::Float64(), 1493 kNoWriteBarrier}; 1494 1495 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, 1496 t.p1, t.start, t.start); 1497 t.Return(load); 1498 t.Lower(); 1499 CHECK_EQ(IrOpcode::kLoadElement, load->opcode()); 1500 CHECK_EQ(t.p0, load->InputAt(0)); 1501 CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0)); 1502 } 1503 1504 1505 TEST(InsertChangeForLoadField) { 1506 // TODO(titzer): test all load/store representation change insertions. 1507 TestingGraph t(Type::Any(), Type::Signed32()); 1508 FieldAccess access = { 1509 kTaggedBase, FixedArrayBase::kHeaderSize, Handle<Name>::null(), 1510 Type::Number(), MachineType::Float64(), kNoWriteBarrier}; 1511 1512 Node* load = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, 1513 t.start, t.start); 1514 t.Return(load); 1515 t.Lower(); 1516 CHECK_EQ(IrOpcode::kLoadField, load->opcode()); 1517 CHECK_EQ(t.p0, load->InputAt(0)); 1518 CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0)); 1519 } 1520 1521 1522 TEST(InsertChangeForStoreElement) { 1523 // TODO(titzer): test all load/store representation change insertions. 1524 TestingGraph t(Type::Any(), Type::Signed32()); 1525 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), 1526 MachineType::Float64(), kFullWriteBarrier}; 1527 1528 Node* store = 1529 t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, 1530 t.jsgraph.Int32Constant(0), t.p1, t.start, t.start); 1531 t.Effect(store); 1532 t.Lower(); 1533 1534 CHECK_EQ(IrOpcode::kStoreElement, store->opcode()); 1535 CHECK_EQ(t.p0, store->InputAt(0)); 1536 CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2)); 1537 } 1538 1539 1540 TEST(InsertChangeForStoreField) { 1541 // TODO(titzer): test all load/store representation change insertions. 1542 TestingGraph t(Type::Any(), Type::Signed32()); 1543 FieldAccess access = { 1544 kTaggedBase, FixedArrayBase::kHeaderSize, Handle<Name>::null(), 1545 Type::Any(), MachineType::Float64(), kNoWriteBarrier}; 1546 1547 Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0, 1548 t.p1, t.start, t.start); 1549 t.Effect(store); 1550 t.Lower(); 1551 1552 CHECK_EQ(IrOpcode::kStoreField, store->opcode()); 1553 CHECK_EQ(t.p0, store->InputAt(0)); 1554 CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(1)); 1555 } 1556 1557 1558 TEST(UpdatePhi) { 1559 TestingGraph t(Type::Any(), Type::Signed32()); 1560 static const MachineType kMachineTypes[] = { 1561 MachineType::Int32(), MachineType::Uint32(), MachineType::Float64()}; 1562 Type* kTypes[] = {Type::Signed32(), Type::Unsigned32(), Type::Number()}; 1563 1564 for (size_t i = 0; i < arraysize(kMachineTypes); i++) { 1565 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, 1566 Handle<Name>::null(), kTypes[i], 1567 kMachineTypes[i], kFullWriteBarrier}; 1568 1569 Node* load0 = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, 1570 t.start, t.start); 1571 Node* load1 = t.graph()->NewNode(t.simplified()->LoadField(access), t.p1, 1572 t.start, t.start); 1573 Node* phi = 1574 t.graph()->NewNode(t.common()->Phi(MachineRepresentation::kTagged, 2), 1575 load0, load1, t.start); 1576 t.Return(t.Use(phi, kMachineTypes[i])); 1577 t.Lower(); 1578 1579 CHECK_EQ(IrOpcode::kPhi, phi->opcode()); 1580 CHECK_EQ(kMachineTypes[i].representation(), PhiRepresentationOf(phi->op())); 1581 } 1582 } 1583 1584 1585 TEST(RunNumberDivide_minus_1_TruncatingToInt32) { 1586 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 1587 Node* num = t.NumberToInt32(t.Parameter(0)); 1588 Node* div = t.NumberDivide(num, t.jsgraph.Constant(-1)); 1589 Node* trunc = t.NumberToInt32(div); 1590 t.Return(trunc); 1591 1592 t.LowerAllNodesAndLowerChanges(); 1593 t.GenerateCode(); 1594 1595 FOR_INT32_INPUTS(i) { 1596 int32_t x = 0 - *i; 1597 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); 1598 } 1599 } 1600 1601 1602 TEST(RunNumberMultiply_TruncatingToInt32) { 1603 int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999}; 1604 1605 for (size_t i = 0; i < arraysize(constants); i++) { 1606 double k = static_cast<double>(constants[i]); 1607 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 1608 Node* num = t.NumberToInt32(t.Parameter(0)); 1609 Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k)); 1610 Node* trunc = t.NumberToInt32(mul); 1611 t.Return(trunc); 1612 1613 t.LowerAllNodesAndLowerChanges(); 1614 t.GenerateCode(); 1615 1616 FOR_INT32_INPUTS(i) { 1617 int32_t x = DoubleToInt32(static_cast<double>(*i) * k); 1618 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); 1619 } 1620 } 1621 } 1622 1623 1624 TEST(RunNumberMultiply_TruncatingToUint32) { 1625 uint32_t constants[] = {0, 1, 2, 3, 4, 100, 1000, 1024, 2048, 3000999}; 1626 1627 for (size_t i = 0; i < arraysize(constants); i++) { 1628 double k = static_cast<double>(constants[i]); 1629 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 1630 Node* num = t.NumberToUint32(t.Parameter(0)); 1631 Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k)); 1632 Node* trunc = t.NumberToUint32(mul); 1633 t.Return(trunc); 1634 1635 t.LowerAllNodesAndLowerChanges(); 1636 t.GenerateCode(); 1637 1638 FOR_UINT32_INPUTS(i) { 1639 uint32_t x = DoubleToUint32(static_cast<double>(*i) * k); 1640 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); 1641 } 1642 } 1643 } 1644 1645 1646 TEST(RunNumberDivide_2_TruncatingToUint32) { 1647 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 1648 Node* num = t.NumberToUint32(t.Parameter(0)); 1649 Node* div = t.NumberDivide(num, t.jsgraph.Constant(2)); 1650 Node* trunc = t.NumberToUint32(div); 1651 t.Return(trunc); 1652 1653 t.LowerAllNodesAndLowerChanges(); 1654 t.GenerateCode(); 1655 1656 FOR_UINT32_INPUTS(i) { 1657 uint32_t x = DoubleToUint32(static_cast<double>(*i / 2.0)); 1658 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); 1659 } 1660 } 1661 1662 1663 TEST(NumberMultiply_ConstantOutOfRange) { 1664 TestingGraph t(Type::Signed32()); 1665 Node* k = t.jsgraph.Constant(1000000023); 1666 Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k); 1667 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul); 1668 t.Return(trunc); 1669 t.Lower(); 1670 1671 CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode()); 1672 } 1673 1674 1675 TEST(NumberMultiply_NonTruncating) { 1676 TestingGraph t(Type::Signed32()); 1677 Node* k = t.jsgraph.Constant(111); 1678 Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k); 1679 t.Return(mul); 1680 t.Lower(); 1681 1682 CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode()); 1683 } 1684 1685 1686 TEST(NumberDivide_TruncatingToInt32) { 1687 int32_t constants[] = {-100, -10, 1, 4, 100, 1000}; 1688 1689 for (size_t i = 0; i < arraysize(constants); i++) { 1690 TestingGraph t(Type::Signed32()); 1691 Node* k = t.jsgraph.Constant(constants[i]); 1692 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); 1693 Node* use = t.Use(div, MachineType::Int32()); 1694 t.Return(use); 1695 t.Lower(); 1696 1697 CHECK_EQ(IrOpcode::kInt32Div, use->InputAt(0)->opcode()); 1698 } 1699 } 1700 1701 1702 TEST(RunNumberDivide_TruncatingToInt32) { 1703 int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048}; 1704 1705 for (size_t i = 0; i < arraysize(constants); i++) { 1706 int32_t k = constants[i]; 1707 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 1708 Node* num = t.NumberToInt32(t.Parameter(0)); 1709 Node* div = t.NumberDivide(num, t.jsgraph.Constant(k)); 1710 Node* trunc = t.NumberToInt32(div); 1711 t.Return(trunc); 1712 1713 t.LowerAllNodesAndLowerChanges(); 1714 t.GenerateCode(); 1715 1716 FOR_INT32_INPUTS(i) { 1717 if (*i == INT_MAX) continue; // exclude max int. 1718 int32_t x = DoubleToInt32(static_cast<double>(*i) / k); 1719 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); 1720 } 1721 } 1722 } 1723 1724 1725 TEST(NumberDivide_TruncatingToUint32) { 1726 double constants[] = {1, 3, 100, 1000, 100998348}; 1727 1728 for (size_t i = 0; i < arraysize(constants); i++) { 1729 TestingGraph t(Type::Unsigned32()); 1730 Node* k = t.jsgraph.Constant(constants[i]); 1731 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); 1732 Node* use = t.Use(div, MachineType::Uint32()); 1733 t.Return(use); 1734 t.Lower(); 1735 1736 CHECK_EQ(IrOpcode::kUint32Div, use->InputAt(0)->opcode()); 1737 } 1738 } 1739 1740 1741 TEST(RunNumberDivide_TruncatingToUint32) { 1742 uint32_t constants[] = {100, 10, 1, 1, 2, 4, 1000, 1024, 2048}; 1743 1744 for (size_t i = 0; i < arraysize(constants); i++) { 1745 uint32_t k = constants[i]; 1746 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 1747 Node* num = t.NumberToUint32(t.Parameter(0)); 1748 Node* div = t.NumberDivide(num, t.jsgraph.Constant(static_cast<double>(k))); 1749 Node* trunc = t.NumberToUint32(div); 1750 t.Return(trunc); 1751 1752 t.LowerAllNodesAndLowerChanges(); 1753 t.GenerateCode(); 1754 1755 FOR_UINT32_INPUTS(i) { 1756 uint32_t x = *i / k; 1757 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); 1758 } 1759 } 1760 } 1761 1762 1763 TEST(NumberDivide_BadConstants) { 1764 { 1765 TestingGraph t(Type::Signed32()); 1766 Node* k = t.jsgraph.Constant(-1); 1767 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); 1768 Node* use = t.Use(div, MachineType::Int32()); 1769 t.Return(use); 1770 t.Lower(); 1771 1772 CHECK_EQ(IrOpcode::kInt32Sub, use->InputAt(0)->opcode()); 1773 } 1774 1775 { 1776 TestingGraph t(Type::Signed32()); 1777 Node* k = t.jsgraph.Constant(0); 1778 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); 1779 Node* use = t.Use(div, MachineType::Int32()); 1780 t.Return(use); 1781 t.Lower(); 1782 1783 CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode()); 1784 CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0))); 1785 } 1786 1787 { 1788 TestingGraph t(Type::Unsigned32()); 1789 Node* k = t.jsgraph.Constant(0); 1790 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); 1791 Node* use = t.Use(div, MachineType::Uint32()); 1792 t.Return(use); 1793 t.Lower(); 1794 1795 CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode()); 1796 CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0))); 1797 } 1798 } 1799 1800 1801 TEST(NumberModulus_TruncatingToInt32) { 1802 int32_t constants[] = {-100, -10, 1, 4, 100, 1000}; 1803 1804 for (size_t i = 0; i < arraysize(constants); i++) { 1805 TestingGraph t(Type::Signed32()); 1806 Node* k = t.jsgraph.Constant(constants[i]); 1807 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); 1808 Node* use = t.Use(mod, MachineType::Int32()); 1809 t.Return(use); 1810 t.Lower(); 1811 1812 CHECK_EQ(IrOpcode::kInt32Mod, use->InputAt(0)->opcode()); 1813 } 1814 } 1815 1816 1817 TEST(RunNumberModulus_TruncatingToInt32) { 1818 int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048}; 1819 1820 for (size_t i = 0; i < arraysize(constants); i++) { 1821 int32_t k = constants[i]; 1822 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 1823 Node* num = t.NumberToInt32(t.Parameter(0)); 1824 Node* mod = t.NumberModulus(num, t.jsgraph.Constant(k)); 1825 Node* trunc = t.NumberToInt32(mod); 1826 t.Return(trunc); 1827 1828 t.LowerAllNodesAndLowerChanges(); 1829 t.GenerateCode(); 1830 1831 FOR_INT32_INPUTS(i) { 1832 if (*i == INT_MAX) continue; // exclude max int. 1833 int32_t x = DoubleToInt32(std::fmod(static_cast<double>(*i), k)); 1834 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); 1835 } 1836 } 1837 } 1838 1839 1840 TEST(NumberModulus_TruncatingToUint32) { 1841 double constants[] = {1, 3, 100, 1000, 100998348}; 1842 1843 for (size_t i = 0; i < arraysize(constants); i++) { 1844 TestingGraph t(Type::Unsigned32()); 1845 Node* k = t.jsgraph.Constant(constants[i]); 1846 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); 1847 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod); 1848 t.Return(trunc); 1849 t.Lower(); 1850 1851 CHECK_EQ(IrOpcode::kUint32Mod, t.ret->InputAt(0)->InputAt(0)->opcode()); 1852 } 1853 } 1854 1855 1856 TEST(RunNumberModulus_TruncatingToUint32) { 1857 uint32_t constants[] = {1, 2, 100, 1000, 1024, 2048}; 1858 1859 for (size_t i = 0; i < arraysize(constants); i++) { 1860 uint32_t k = constants[i]; 1861 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged()); 1862 Node* num = t.NumberToUint32(t.Parameter(0)); 1863 Node* mod = 1864 t.NumberModulus(num, t.jsgraph.Constant(static_cast<double>(k))); 1865 Node* trunc = t.NumberToUint32(mod); 1866 t.Return(trunc); 1867 1868 t.LowerAllNodesAndLowerChanges(); 1869 t.GenerateCode(); 1870 1871 FOR_UINT32_INPUTS(i) { 1872 uint32_t x = *i % k; 1873 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); 1874 } 1875 } 1876 } 1877 1878 1879 TEST(NumberModulus_Int32) { 1880 int32_t constants[] = {-100, -10, 1, 4, 100, 1000}; 1881 1882 for (size_t i = 0; i < arraysize(constants); i++) { 1883 TestingGraph t(Type::Signed32()); 1884 Node* k = t.jsgraph.Constant(constants[i]); 1885 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); 1886 t.Return(mod); 1887 t.Lower(); 1888 1889 CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode()); // Pesky -0 behavior. 1890 } 1891 } 1892 1893 1894 TEST(NumberModulus_Uint32) { 1895 const double kConstants[] = {2, 100, 1000, 1024, 2048}; 1896 const MachineType kTypes[] = {MachineType::Int32(), MachineType::Uint32()}; 1897 1898 for (auto const type : kTypes) { 1899 for (auto const c : kConstants) { 1900 TestingGraph t(Type::Unsigned32()); 1901 Node* k = t.jsgraph.Constant(c); 1902 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); 1903 Node* use = t.Use(mod, type); 1904 t.Return(use); 1905 t.Lower(); 1906 1907 CHECK_EQ(IrOpcode::kUint32Mod, use->InputAt(0)->opcode()); 1908 } 1909 } 1910 } 1911 1912 1913 TEST(PhiRepresentation) { 1914 HandleAndZoneScope scope; 1915 Zone* z = scope.main_zone(); 1916 1917 struct TestData { 1918 Type* arg1; 1919 Type* arg2; 1920 MachineType use; 1921 MachineRepresentation expected; 1922 }; 1923 1924 TestData test_data[] = { 1925 {Type::Signed32(), Type::Unsigned32(), MachineType::Int32(), 1926 MachineRepresentation::kWord32}, 1927 {Type::Signed32(), Type::Unsigned32(), MachineType::Uint32(), 1928 MachineRepresentation::kWord32}, 1929 {Type::Signed32(), Type::Signed32(), MachineType::Int32(), 1930 MachineRepresentation::kWord32}, 1931 {Type::Unsigned32(), Type::Unsigned32(), MachineType::Int32(), 1932 MachineRepresentation::kWord32}, 1933 {Type::Number(), Type::Signed32(), MachineType::Int32(), 1934 MachineRepresentation::kWord32}}; 1935 1936 for (auto const d : test_data) { 1937 TestingGraph t(d.arg1, d.arg2, Type::Boolean()); 1938 1939 Node* br = t.graph()->NewNode(t.common()->Branch(), t.p2, t.start); 1940 Node* tb = t.graph()->NewNode(t.common()->IfTrue(), br); 1941 Node* fb = t.graph()->NewNode(t.common()->IfFalse(), br); 1942 Node* m = t.graph()->NewNode(t.common()->Merge(2), tb, fb); 1943 1944 Node* phi = t.graph()->NewNode( 1945 t.common()->Phi(MachineRepresentation::kTagged, 2), t.p0, t.p1, m); 1946 1947 Type* phi_type = Type::Union(d.arg1, d.arg2, z); 1948 NodeProperties::SetType(phi, phi_type); 1949 1950 Node* use = t.Use(phi, d.use); 1951 t.Return(use); 1952 t.Lower(); 1953 1954 CHECK_EQ(d.expected, PhiRepresentationOf(phi->op())); 1955 } 1956 } 1957 1958 } // namespace compiler 1959 } // namespace internal 1960 } // namespace v8 1961