| 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/compiler/access-builder.h" | 7 #include "src/compiler/access-builder.h" |
| 8 #include "src/compiler/control-builders.h" | 8 #include "src/compiler/control-builders.h" |
| 9 #include "src/compiler/generic-node-inl.h" | 9 #include "src/compiler/generic-node-inl.h" |
| 10 #include "src/compiler/graph-visualizer.h" | 10 #include "src/compiler/graph-visualizer.h" |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 } | 318 } |
| 319 | 319 |
| 320 | 320 |
| 321 TEST(RunLoadElementFromUntaggedBase) { | 321 TEST(RunLoadElementFromUntaggedBase) { |
| 322 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3), | 322 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3), |
| 323 Smi::FromInt(4), Smi::FromInt(5)}; | 323 Smi::FromInt(4), Smi::FromInt(5)}; |
| 324 | 324 |
| 325 for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes | 325 for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes |
| 326 for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index | 326 for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index |
| 327 int offset = static_cast<int>(i * sizeof(Smi*)); | 327 int offset = static_cast<int>(i * sizeof(Smi*)); |
| 328 ElementAccess access = {kUntaggedBase, offset, Type::Integral32(), | 328 ElementAccess access = {kNoBoundsCheck, kUntaggedBase, offset, |
| 329 kMachAnyTagged}; | 329 Type::Integral32(), kMachAnyTagged}; |
| 330 | 330 |
| 331 SimplifiedLoweringTester<Object*> t; | 331 SimplifiedLoweringTester<Object*> t; |
| 332 Node* load = t.LoadElement( | 332 Node* load = t.LoadElement( |
| 333 access, t.PointerConstant(smis), t.Int32Constant(static_cast<int>(j)), | 333 access, t.PointerConstant(smis), t.Int32Constant(static_cast<int>(j)), |
| 334 t.Int32Constant(static_cast<int>(arraysize(smis)))); | 334 t.Int32Constant(static_cast<int>(arraysize(smis)))); |
| 335 t.Return(load); | 335 t.Return(load); |
| 336 t.LowerAllNodes(); | 336 t.LowerAllNodes(); |
| 337 | 337 |
| 338 if (!Pipeline::SupportedTarget()) continue; | 338 if (!Pipeline::SupportedTarget()) continue; |
| 339 | 339 |
| 340 for (int k = -5; k <= 5; k++) { | 340 for (int k = -5; k <= 5; k++) { |
| 341 Smi* expected = Smi::FromInt(k); | 341 Smi* expected = Smi::FromInt(k); |
| 342 smis[i + j] = expected; | 342 smis[i + j] = expected; |
| 343 CHECK_EQ(expected, t.Call()); | 343 CHECK_EQ(expected, t.Call()); |
| 344 } | 344 } |
| 345 } | 345 } |
| 346 } | 346 } |
| 347 } | 347 } |
| 348 | 348 |
| 349 | 349 |
| 350 TEST(RunStoreElementFromUntaggedBase) { | 350 TEST(RunStoreElementFromUntaggedBase) { |
| 351 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3), | 351 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3), |
| 352 Smi::FromInt(4), Smi::FromInt(5)}; | 352 Smi::FromInt(4), Smi::FromInt(5)}; |
| 353 | 353 |
| 354 for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes | 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 | 355 for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index |
| 356 int offset = static_cast<int>(i * sizeof(Smi*)); | 356 int offset = static_cast<int>(i * sizeof(Smi*)); |
| 357 ElementAccess access = {kUntaggedBase, offset, Type::Integral32(), | 357 ElementAccess access = {kNoBoundsCheck, kUntaggedBase, offset, |
| 358 kMachAnyTagged}; | 358 Type::Integral32(), kMachAnyTagged}; |
| 359 | 359 |
| 360 SimplifiedLoweringTester<Object*> t(kMachAnyTagged); | 360 SimplifiedLoweringTester<Object*> t(kMachAnyTagged); |
| 361 Node* p0 = t.Parameter(0); | 361 Node* p0 = t.Parameter(0); |
| 362 t.StoreElement(access, t.PointerConstant(smis), | 362 t.StoreElement(access, t.PointerConstant(smis), |
| 363 t.Int32Constant(static_cast<int>(j)), | 363 t.Int32Constant(static_cast<int>(j)), |
| 364 t.Int32Constant(static_cast<int>(arraysize(smis))), p0); | 364 t.Int32Constant(static_cast<int>(arraysize(smis))), p0); |
| 365 t.Return(p0); | 365 t.Return(p0); |
| 366 t.LowerAllNodes(); | 366 t.LowerAllNodes(); |
| 367 | 367 |
| 368 if (!Pipeline::SupportedTarget()) continue; | 368 if (!Pipeline::SupportedTarget()) continue; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 if (tagged) { | 510 if (tagged) { |
| 511 E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress()); | 511 E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress()); |
| 512 return raw[index]; | 512 return raw[index]; |
| 513 } else { | 513 } else { |
| 514 return untagged_array[index]; | 514 return untagged_array[index]; |
| 515 } | 515 } |
| 516 } | 516 } |
| 517 | 517 |
| 518 private: | 518 private: |
| 519 ElementAccess GetElementAccess() { | 519 ElementAccess GetElementAccess() { |
| 520 ElementAccess access = {tagged ? kTaggedBase : kUntaggedBase, | 520 ElementAccess access = { |
| 521 tagged ? FixedArrayBase::kHeaderSize : 0, | 521 kNoBoundsCheck, tagged ? kTaggedBase : kUntaggedBase, |
| 522 Type::Any(), rep}; | 522 tagged ? FixedArrayBase::kHeaderSize : 0, Type::Any(), rep}; |
| 523 return access; | 523 return access; |
| 524 } | 524 } |
| 525 | 525 |
| 526 FieldAccess GetFieldAccess(int field) { | 526 FieldAccess GetFieldAccess(int field) { |
| 527 int offset = field * sizeof(E); | 527 int offset = field * sizeof(E); |
| 528 FieldAccess access = {tagged ? kTaggedBase : kUntaggedBase, | 528 FieldAccess access = {tagged ? kTaggedBase : kUntaggedBase, |
| 529 offset + (tagged ? FixedArrayBase::kHeaderSize : 0), | 529 offset + (tagged ? FixedArrayBase::kHeaderSize : 0), |
| 530 Handle<Name>(), Type::Any(), rep}; | 530 Handle<Name>(), Type::Any(), rep}; |
| 531 return access; | 531 return access; |
| 532 } | 532 } |
| (...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1342 } | 1342 } |
| 1343 CHECK_EQ(machine_reps[i], rep.machine_type()); | 1343 CHECK_EQ(machine_reps[i], rep.machine_type()); |
| 1344 } | 1344 } |
| 1345 } | 1345 } |
| 1346 | 1346 |
| 1347 | 1347 |
| 1348 TEST(LowerLoadElement_to_load) { | 1348 TEST(LowerLoadElement_to_load) { |
| 1349 TestingGraph t(Type::Any(), Type::Signed32()); | 1349 TestingGraph t(Type::Any(), Type::Signed32()); |
| 1350 | 1350 |
| 1351 for (size_t i = 0; i < arraysize(machine_reps); i++) { | 1351 for (size_t i = 0; i < arraysize(machine_reps); i++) { |
| 1352 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, | 1352 ElementAccess access = {kNoBoundsCheck, kTaggedBase, |
| 1353 Type::Any(), machine_reps[i]}; | 1353 FixedArrayBase::kHeaderSize, Type::Any(), |
| 1354 machine_reps[i]}; |
| 1354 | 1355 |
| 1355 Node* load = | 1356 Node* load = |
| 1356 t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1, | 1357 t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1, |
| 1357 t.jsgraph.Int32Constant(1024), t.start); | 1358 t.jsgraph.Int32Constant(1024), t.start); |
| 1358 Node* use = t.Use(load, machine_reps[i]); | 1359 Node* use = t.Use(load, machine_reps[i]); |
| 1359 t.Return(use); | 1360 t.Return(use); |
| 1360 t.Lower(); | 1361 t.Lower(); |
| 1361 CHECK_EQ(IrOpcode::kLoad, load->opcode()); | 1362 CHECK_EQ(IrOpcode::kLoad, load->opcode()); |
| 1362 CHECK_EQ(t.p0, load->InputAt(0)); | 1363 CHECK_EQ(t.p0, load->InputAt(0)); |
| 1363 CheckElementAccessArithmetic(access, load); | 1364 CheckElementAccessArithmetic(access, load); |
| 1364 | 1365 |
| 1365 MachineType rep = OpParameter<MachineType>(load); | 1366 MachineType rep = OpParameter<MachineType>(load); |
| 1366 CHECK_EQ(machine_reps[i], rep); | 1367 CHECK_EQ(machine_reps[i], rep); |
| 1367 } | 1368 } |
| 1368 } | 1369 } |
| 1369 | 1370 |
| 1370 | 1371 |
| 1371 TEST(LowerStoreElement_to_store) { | 1372 TEST(LowerStoreElement_to_store) { |
| 1372 TestingGraph t(Type::Any(), Type::Signed32()); | 1373 TestingGraph t(Type::Any(), Type::Signed32()); |
| 1373 | 1374 |
| 1374 for (size_t i = 0; i < arraysize(machine_reps); i++) { | 1375 for (size_t i = 0; i < arraysize(machine_reps); i++) { |
| 1375 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, | 1376 ElementAccess access = {kNoBoundsCheck, kTaggedBase, |
| 1376 Type::Any(), machine_reps[i]}; | 1377 FixedArrayBase::kHeaderSize, Type::Any(), |
| 1378 machine_reps[i]}; |
| 1377 | 1379 |
| 1378 Node* val = t.ExampleWithOutput(machine_reps[i]); | 1380 Node* val = t.ExampleWithOutput(machine_reps[i]); |
| 1379 Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, | 1381 Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, |
| 1380 t.p1, t.jsgraph.Int32Constant(1024), val, | 1382 t.p1, t.jsgraph.Int32Constant(1024), val, |
| 1381 t.start, t.start); | 1383 t.start, t.start); |
| 1382 t.Effect(store); | 1384 t.Effect(store); |
| 1383 t.Lower(); | 1385 t.Lower(); |
| 1384 CHECK_EQ(IrOpcode::kStore, store->opcode()); | 1386 CHECK_EQ(IrOpcode::kStore, store->opcode()); |
| 1385 CHECK_EQ(val, store->InputAt(2)); | 1387 CHECK_EQ(val, store->InputAt(2)); |
| 1386 CheckElementAccessArithmetic(access, store); | 1388 CheckElementAccessArithmetic(access, store); |
| 1387 | 1389 |
| 1388 StoreRepresentation rep = OpParameter<StoreRepresentation>(store); | 1390 StoreRepresentation rep = OpParameter<StoreRepresentation>(store); |
| 1389 if (machine_reps[i] & kRepTagged) { | 1391 if (machine_reps[i] & kRepTagged) { |
| 1390 CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind()); | 1392 CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind()); |
| 1391 } | 1393 } |
| 1392 CHECK_EQ(machine_reps[i], rep.machine_type()); | 1394 CHECK_EQ(machine_reps[i], rep.machine_type()); |
| 1393 } | 1395 } |
| 1394 } | 1396 } |
| 1395 | 1397 |
| 1396 | 1398 |
| 1397 TEST(InsertChangeForLoadElementIndex) { | 1399 TEST(InsertChangeForLoadElementIndex) { |
| 1398 // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) => | 1400 // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) => |
| 1399 // Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k)) | 1401 // Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k)) |
| 1400 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any()); | 1402 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any()); |
| 1401 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), | 1403 ElementAccess access = {kNoBoundsCheck, kTaggedBase, |
| 1404 FixedArrayBase::kHeaderSize, Type::Any(), |
| 1402 kMachAnyTagged}; | 1405 kMachAnyTagged}; |
| 1403 | 1406 |
| 1404 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, | 1407 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, |
| 1405 t.p1, t.p2, t.start); | 1408 t.p1, t.p2, t.start); |
| 1406 t.Return(load); | 1409 t.Return(load); |
| 1407 t.Lower(); | 1410 t.Lower(); |
| 1408 CHECK_EQ(IrOpcode::kLoad, load->opcode()); | 1411 CHECK_EQ(IrOpcode::kLoad, load->opcode()); |
| 1409 CHECK_EQ(t.p0, load->InputAt(0)); | 1412 CHECK_EQ(t.p0, load->InputAt(0)); |
| 1410 | 1413 |
| 1411 Node* index = CheckElementAccessArithmetic(access, load); | 1414 Node* index = CheckElementAccessArithmetic(access, load); |
| 1412 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, index); | 1415 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, index); |
| 1413 } | 1416 } |
| 1414 | 1417 |
| 1415 | 1418 |
| 1416 TEST(InsertChangeForStoreElementIndex) { | 1419 TEST(InsertChangeForStoreElementIndex) { |
| 1417 // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) => | 1420 // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) => |
| 1418 // Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val) | 1421 // Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val) |
| 1419 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any()); | 1422 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any()); |
| 1420 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), | 1423 ElementAccess access = {kNoBoundsCheck, kTaggedBase, |
| 1424 FixedArrayBase::kHeaderSize, Type::Any(), |
| 1421 kMachAnyTagged}; | 1425 kMachAnyTagged}; |
| 1422 | 1426 |
| 1423 Node* store = | 1427 Node* store = |
| 1424 t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, t.p2, | 1428 t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, t.p2, |
| 1425 t.jsgraph.TrueConstant(), t.start, t.start); | 1429 t.jsgraph.TrueConstant(), t.start, t.start); |
| 1426 t.Effect(store); | 1430 t.Effect(store); |
| 1427 t.Lower(); | 1431 t.Lower(); |
| 1428 CHECK_EQ(IrOpcode::kStore, store->opcode()); | 1432 CHECK_EQ(IrOpcode::kStore, store->opcode()); |
| 1429 CHECK_EQ(t.p0, store->InputAt(0)); | 1433 CHECK_EQ(t.p0, store->InputAt(0)); |
| 1430 | 1434 |
| 1431 Node* index = CheckElementAccessArithmetic(access, store); | 1435 Node* index = CheckElementAccessArithmetic(access, store); |
| 1432 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, index); | 1436 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, index); |
| 1433 } | 1437 } |
| 1434 | 1438 |
| 1435 | 1439 |
| 1436 TEST(InsertChangeForLoadElement) { | 1440 TEST(InsertChangeForLoadElement) { |
| 1437 // TODO(titzer): test all load/store representation change insertions. | 1441 // TODO(titzer): test all load/store representation change insertions. |
| 1438 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any()); | 1442 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any()); |
| 1439 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), | 1443 ElementAccess access = {kNoBoundsCheck, kTaggedBase, |
| 1444 FixedArrayBase::kHeaderSize, Type::Any(), |
| 1440 kMachFloat64}; | 1445 kMachFloat64}; |
| 1441 | 1446 |
| 1442 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, | 1447 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, |
| 1443 t.p1, t.p1, t.start); | 1448 t.p1, t.p1, t.start); |
| 1444 t.Return(load); | 1449 t.Return(load); |
| 1445 t.Lower(); | 1450 t.Lower(); |
| 1446 CHECK_EQ(IrOpcode::kLoad, load->opcode()); | 1451 CHECK_EQ(IrOpcode::kLoad, load->opcode()); |
| 1447 CHECK_EQ(t.p0, load->InputAt(0)); | 1452 CHECK_EQ(t.p0, load->InputAt(0)); |
| 1448 CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0)); | 1453 CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0)); |
| 1449 } | 1454 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1461 t.Lower(); | 1466 t.Lower(); |
| 1462 CHECK_EQ(IrOpcode::kLoad, load->opcode()); | 1467 CHECK_EQ(IrOpcode::kLoad, load->opcode()); |
| 1463 CHECK_EQ(t.p0, load->InputAt(0)); | 1468 CHECK_EQ(t.p0, load->InputAt(0)); |
| 1464 CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0)); | 1469 CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0)); |
| 1465 } | 1470 } |
| 1466 | 1471 |
| 1467 | 1472 |
| 1468 TEST(InsertChangeForStoreElement) { | 1473 TEST(InsertChangeForStoreElement) { |
| 1469 // TODO(titzer): test all load/store representation change insertions. | 1474 // TODO(titzer): test all load/store representation change insertions. |
| 1470 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any()); | 1475 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any()); |
| 1471 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), | 1476 ElementAccess access = {kNoBoundsCheck, kTaggedBase, |
| 1477 FixedArrayBase::kHeaderSize, Type::Any(), |
| 1472 kMachFloat64}; | 1478 kMachFloat64}; |
| 1473 | 1479 |
| 1474 Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, | 1480 Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, |
| 1475 t.jsgraph.Int32Constant(0), t.p2, t.p1, | 1481 t.jsgraph.Int32Constant(0), t.p2, t.p1, |
| 1476 t.start, t.start); | 1482 t.start, t.start); |
| 1477 t.Effect(store); | 1483 t.Effect(store); |
| 1478 t.Lower(); | 1484 t.Lower(); |
| 1479 | 1485 |
| 1480 CHECK_EQ(IrOpcode::kStore, store->opcode()); | 1486 CHECK_EQ(IrOpcode::kStore, store->opcode()); |
| 1481 CHECK_EQ(t.p0, store->InputAt(0)); | 1487 CHECK_EQ(t.p0, store->InputAt(0)); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1516 Node* phi = t.graph()->NewNode(t.common()->Phi(kMachAnyTagged, 2), load0, | 1522 Node* phi = t.graph()->NewNode(t.common()->Phi(kMachAnyTagged, 2), load0, |
| 1517 load1, t.start); | 1523 load1, t.start); |
| 1518 t.Return(t.Use(phi, kMachineTypes[i])); | 1524 t.Return(t.Use(phi, kMachineTypes[i])); |
| 1519 t.Lower(); | 1525 t.Lower(); |
| 1520 | 1526 |
| 1521 CHECK_EQ(IrOpcode::kPhi, phi->opcode()); | 1527 CHECK_EQ(IrOpcode::kPhi, phi->opcode()); |
| 1522 CHECK_EQ(RepresentationOf(kMachineTypes[i]), | 1528 CHECK_EQ(RepresentationOf(kMachineTypes[i]), |
| 1523 RepresentationOf(OpParameter<MachineType>(phi))); | 1529 RepresentationOf(OpParameter<MachineType>(phi))); |
| 1524 } | 1530 } |
| 1525 } | 1531 } |
| OLD | NEW |