| 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 "src/compiler/instruction-selector-impl.h" | 5 #include "src/compiler/instruction-selector-impl.h" |
| 6 #include "src/compiler/node-matchers.h" | 6 #include "src/compiler/node-matchers.h" |
| 7 #include "src/compiler/node-properties.h" | 7 #include "src/compiler/node-properties.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 1433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1444 } | 1444 } |
| 1445 // Now all pushes can be done in pairs. | 1445 // Now all pushes can be done in pairs. |
| 1446 for (; slot >= 0; slot -= 2) { | 1446 for (; slot >= 0; slot -= 2) { |
| 1447 Emit(kArm64PokePair, g.NoOutput(), g.UseRegister((*arguments)[slot]), | 1447 Emit(kArm64PokePair, g.NoOutput(), g.UseRegister((*arguments)[slot]), |
| 1448 g.UseRegister((*arguments)[slot - 1]), g.TempImmediate(slot)); | 1448 g.UseRegister((*arguments)[slot - 1]), g.TempImmediate(slot)); |
| 1449 } | 1449 } |
| 1450 } | 1450 } |
| 1451 } | 1451 } |
| 1452 | 1452 |
| 1453 | 1453 |
| 1454 void InstructionSelector::VisitTailCall(Node* node) { | 1454 bool InstructionSelector::IsTailCallAddressImmediate() { return false; } |
| 1455 Arm64OperandGenerator g(this); | |
| 1456 const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node); | |
| 1457 DCHECK_NE(0, descriptor->flags() & CallDescriptor::kSupportsTailCalls); | |
| 1458 DCHECK_EQ(0, descriptor->flags() & CallDescriptor::kPatchableCallSite); | |
| 1459 DCHECK_EQ(0, descriptor->flags() & CallDescriptor::kNeedsNopAfterCall); | |
| 1460 | |
| 1461 // TODO(turbofan): Relax restriction for stack parameters. | |
| 1462 if (linkage()->GetIncomingDescriptor()->CanTailCall(node)) { | |
| 1463 CallBuffer buffer(zone(), descriptor, nullptr); | |
| 1464 | |
| 1465 // Compute InstructionOperands for inputs and outputs. | |
| 1466 // TODO(turbofan): on ARM64 it's probably better to use the code object in a | |
| 1467 // register if there are multiple uses of it. Improve constant pool and the | |
| 1468 // heuristics in the register allocator for where to emit constants. | |
| 1469 InitializeCallBuffer(node, &buffer, true, false); | |
| 1470 | |
| 1471 // Select the appropriate opcode based on the call type. | |
| 1472 InstructionCode opcode; | |
| 1473 switch (descriptor->kind()) { | |
| 1474 case CallDescriptor::kCallCodeObject: | |
| 1475 opcode = kArchTailCallCodeObject; | |
| 1476 break; | |
| 1477 case CallDescriptor::kCallJSFunction: | |
| 1478 opcode = kArchTailCallJSFunction; | |
| 1479 break; | |
| 1480 default: | |
| 1481 UNREACHABLE(); | |
| 1482 return; | |
| 1483 } | |
| 1484 opcode |= MiscField::encode(descriptor->flags()); | |
| 1485 | |
| 1486 // Emit the tailcall instruction. | |
| 1487 Emit(opcode, 0, nullptr, buffer.instruction_args.size(), | |
| 1488 &buffer.instruction_args.front()); | |
| 1489 } else { | |
| 1490 FrameStateDescriptor* frame_state_descriptor = nullptr; | |
| 1491 if (descriptor->NeedsFrameState()) { | |
| 1492 frame_state_descriptor = GetFrameStateDescriptor( | |
| 1493 node->InputAt(static_cast<int>(descriptor->InputCount()))); | |
| 1494 } | |
| 1495 | |
| 1496 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); | |
| 1497 | |
| 1498 // Compute InstructionOperands for inputs and outputs. | |
| 1499 // TODO(turbofan): on ARM64 it's probably better to use the code object in a | |
| 1500 // register if there are multiple uses of it. Improve constant pool and the | |
| 1501 // heuristics in the register allocator for where to emit constants. | |
| 1502 InitializeCallBuffer(node, &buffer, true, false); | |
| 1503 | |
| 1504 // Push the arguments to the stack. | |
| 1505 int aligned_push_count = static_cast<int>(buffer.pushed_nodes.size()); | |
| 1506 bool pushed_count_uneven = aligned_push_count & 1; | |
| 1507 // TODO(dcarney): claim and poke probably take small immediates, | |
| 1508 // loop here or whatever. | |
| 1509 // Bump the stack pointer(s). | |
| 1510 if (aligned_push_count > 0) { | |
| 1511 // TODO(dcarney): it would be better to bump the csp here only | |
| 1512 // and emit paired stores with increment for non c frames. | |
| 1513 Emit(kArm64Claim, g.NoOutput(), g.TempImmediate(aligned_push_count)); | |
| 1514 } | |
| 1515 // Move arguments to the stack. | |
| 1516 { | |
| 1517 int slot = aligned_push_count - 1; | |
| 1518 // Emit the uneven pushes. | |
| 1519 if (pushed_count_uneven) { | |
| 1520 Node* input = buffer.pushed_nodes[slot]; | |
| 1521 Emit(kArm64Poke, g.NoOutput(), g.UseRegister(input), | |
| 1522 g.TempImmediate(slot)); | |
| 1523 slot--; | |
| 1524 } | |
| 1525 // Now all pushes can be done in pairs. | |
| 1526 for (; slot >= 0; slot -= 2) { | |
| 1527 Emit(kArm64PokePair, g.NoOutput(), | |
| 1528 g.UseRegister(buffer.pushed_nodes[slot]), | |
| 1529 g.UseRegister(buffer.pushed_nodes[slot - 1]), | |
| 1530 g.TempImmediate(slot)); | |
| 1531 } | |
| 1532 } | |
| 1533 | |
| 1534 // Select the appropriate opcode based on the call type. | |
| 1535 InstructionCode opcode; | |
| 1536 switch (descriptor->kind()) { | |
| 1537 case CallDescriptor::kCallCodeObject: { | |
| 1538 opcode = kArchCallCodeObject; | |
| 1539 break; | |
| 1540 } | |
| 1541 case CallDescriptor::kCallJSFunction: | |
| 1542 opcode = kArchCallJSFunction; | |
| 1543 break; | |
| 1544 default: | |
| 1545 UNREACHABLE(); | |
| 1546 return; | |
| 1547 } | |
| 1548 opcode |= MiscField::encode(descriptor->flags()); | |
| 1549 | |
| 1550 // Emit the call instruction. | |
| 1551 size_t const output_count = buffer.outputs.size(); | |
| 1552 auto* outputs = output_count ? &buffer.outputs.front() : nullptr; | |
| 1553 Emit(opcode, output_count, outputs, buffer.instruction_args.size(), | |
| 1554 &buffer.instruction_args.front())->MarkAsCall(); | |
| 1555 Emit(kArchRet, 0, nullptr, output_count, outputs); | |
| 1556 } | |
| 1557 } | |
| 1558 | 1455 |
| 1559 | 1456 |
| 1560 namespace { | 1457 namespace { |
| 1561 | 1458 |
| 1562 // Shared routine for multiple compare operations. | 1459 // Shared routine for multiple compare operations. |
| 1563 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 1460 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
| 1564 InstructionOperand left, InstructionOperand right, | 1461 InstructionOperand left, InstructionOperand right, |
| 1565 FlagsContinuation* cont) { | 1462 FlagsContinuation* cont) { |
| 1566 Arm64OperandGenerator g(selector); | 1463 Arm64OperandGenerator g(selector); |
| 1567 opcode = cont->Encode(opcode); | 1464 opcode = cont->Encode(opcode); |
| (...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2065 MachineOperatorBuilder::kFloat64RoundTruncate | | 1962 MachineOperatorBuilder::kFloat64RoundTruncate | |
| 2066 MachineOperatorBuilder::kFloat64RoundTiesAway | | 1963 MachineOperatorBuilder::kFloat64RoundTiesAway | |
| 2067 MachineOperatorBuilder::kWord32ShiftIsSafe | | 1964 MachineOperatorBuilder::kWord32ShiftIsSafe | |
| 2068 MachineOperatorBuilder::kInt32DivIsSafe | | 1965 MachineOperatorBuilder::kInt32DivIsSafe | |
| 2069 MachineOperatorBuilder::kUint32DivIsSafe; | 1966 MachineOperatorBuilder::kUint32DivIsSafe; |
| 2070 } | 1967 } |
| 2071 | 1968 |
| 2072 } // namespace compiler | 1969 } // namespace compiler |
| 2073 } // namespace internal | 1970 } // namespace internal |
| 2074 } // namespace v8 | 1971 } // namespace v8 |
| OLD | NEW |