| 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 <algorithm> | 5 #include <algorithm> |
| 6 | 6 |
| 7 #include "src/base/adapters.h" | 7 #include "src/base/adapters.h" |
| 8 #include "src/compiler/instruction-selector-impl.h" | 8 #include "src/compiler/instruction-selector-impl.h" |
| 9 #include "src/compiler/node-matchers.h" | 9 #include "src/compiler/node-matchers.h" |
| 10 #include "src/compiler/node-properties.h" | 10 #include "src/compiler/node-properties.h" |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 } | 30 } |
| 31 case IrOpcode::kNumberConstant: { | 31 case IrOpcode::kNumberConstant: { |
| 32 const double value = OpParameter<double>(node); | 32 const double value = OpParameter<double>(node); |
| 33 return bit_cast<int64_t>(value) == 0; | 33 return bit_cast<int64_t>(value) == 0; |
| 34 } | 34 } |
| 35 default: | 35 default: |
| 36 return false; | 36 return false; |
| 37 } | 37 } |
| 38 } | 38 } |
| 39 | 39 |
| 40 bool CanBeMemoryOperand(InstructionCode opcode, Node* node, Node* input) { | 40 bool CanBeMemoryOperand(InstructionCode opcode, Node* node, Node* input, |
| 41 int effect_level) { |
| 41 if (input->opcode() != IrOpcode::kLoad || | 42 if (input->opcode() != IrOpcode::kLoad || |
| 42 !selector()->CanCover(node, input)) { | 43 !selector()->CanCover(node, input)) { |
| 43 return false; | 44 return false; |
| 44 } | 45 } |
| 46 if (effect_level != selector()->GetEffectLevel(input)) { |
| 47 return false; |
| 48 } |
| 45 MachineRepresentation rep = | 49 MachineRepresentation rep = |
| 46 LoadRepresentationOf(input->op()).representation(); | 50 LoadRepresentationOf(input->op()).representation(); |
| 47 switch (opcode) { | 51 switch (opcode) { |
| 48 case kX64Cmp: | 52 case kX64Cmp: |
| 49 case kX64Test: | 53 case kX64Test: |
| 50 return rep == MachineRepresentation::kWord64 || | 54 return rep == MachineRepresentation::kWord64 || |
| 51 rep == MachineRepresentation::kTagged; | 55 rep == MachineRepresentation::kTagged; |
| 52 case kX64Cmp32: | 56 case kX64Cmp32: |
| 53 case kX64Test32: | 57 case kX64Test32: |
| 54 return rep == MachineRepresentation::kWord32; | 58 return rep == MachineRepresentation::kWord32; |
| (...skipping 1444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1499 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 1503 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
| 1500 Node* left, Node* right, FlagsContinuation* cont, | 1504 Node* left, Node* right, FlagsContinuation* cont, |
| 1501 bool commutative) { | 1505 bool commutative) { |
| 1502 X64OperandGenerator g(selector); | 1506 X64OperandGenerator g(selector); |
| 1503 if (commutative && g.CanBeBetterLeftOperand(right)) { | 1507 if (commutative && g.CanBeBetterLeftOperand(right)) { |
| 1504 std::swap(left, right); | 1508 std::swap(left, right); |
| 1505 } | 1509 } |
| 1506 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont); | 1510 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont); |
| 1507 } | 1511 } |
| 1508 | 1512 |
| 1509 bool InferMachineRepresentation(Node* node, | |
| 1510 MachineRepresentation* representation) { | |
| 1511 if (node->opcode() == IrOpcode::kLoad) { | |
| 1512 *representation = LoadRepresentationOf(node->op()).representation(); | |
| 1513 return true; | |
| 1514 } | |
| 1515 int64_t value = 0; | |
| 1516 switch (node->opcode()) { | |
| 1517 case IrOpcode::kInt32Constant: | |
| 1518 value = OpParameter<int32_t>(node->op()); | |
| 1519 break; | |
| 1520 case IrOpcode::kInt64Constant: | |
| 1521 value = OpParameter<int64_t>(node->op()); | |
| 1522 break; | |
| 1523 default: | |
| 1524 return false; | |
| 1525 } | |
| 1526 if (is_int8(value)) { | |
| 1527 *representation = MachineRepresentation::kWord8; | |
| 1528 } else if (is_int16(value)) { | |
| 1529 *representation = MachineRepresentation::kWord16; | |
| 1530 } else if (is_int32(value)) { | |
| 1531 *representation = MachineRepresentation::kWord32; | |
| 1532 } else { | |
| 1533 return false; | |
| 1534 } | |
| 1535 return true; | |
| 1536 } | |
| 1537 | |
| 1538 // Tries to match the size of the given opcode to that of the operands, if | 1513 // Tries to match the size of the given opcode to that of the operands, if |
| 1539 // possible. | 1514 // possible. |
| 1540 InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left, | 1515 InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left, |
| 1541 Node* right) { | 1516 Node* right) { |
| 1542 if (opcode != kX64Cmp32 && opcode != kX64Test32) { | 1517 if (opcode != kX64Cmp32 && opcode != kX64Test32) { |
| 1543 return opcode; | 1518 return opcode; |
| 1544 } | 1519 } |
| 1545 // We only do this if at least one of the two operands is a load. | 1520 // Currently, if one of the two operands is not a Load, we don't know what its |
| 1546 // TODO(epertoso): we can probably get some size information out of phi nodes. | 1521 // machine representation is, so we bail out. |
| 1547 if (left->opcode() != IrOpcode::kLoad && right->opcode() != IrOpcode::kLoad) { | 1522 // TODO(epertoso): we can probably get some size information out of immediates |
| 1523 // and phi nodes. |
| 1524 if (left->opcode() != IrOpcode::kLoad || right->opcode() != IrOpcode::kLoad) { |
| 1548 return opcode; | 1525 return opcode; |
| 1549 } | 1526 } |
| 1550 MachineRepresentation left_representation, right_representation; | 1527 // If the load representations don't match, both operands will be |
| 1551 if (!InferMachineRepresentation(left, &left_representation) || | 1528 // zero/sign-extended to 32bit. |
| 1552 !InferMachineRepresentation(right, &right_representation)) { | 1529 LoadRepresentation left_representation = LoadRepresentationOf(left->op()); |
| 1530 if (left_representation != LoadRepresentationOf(right->op())) { |
| 1553 return opcode; | 1531 return opcode; |
| 1554 } | 1532 } |
| 1555 // If the representations don't match, both operands will be | 1533 switch (left_representation.representation()) { |
| 1556 // zero/sign-extended to 32bit. | |
| 1557 if (left_representation != right_representation) { | |
| 1558 return opcode; | |
| 1559 } | |
| 1560 switch (left_representation) { | |
| 1561 case MachineRepresentation::kBit: | 1534 case MachineRepresentation::kBit: |
| 1562 case MachineRepresentation::kWord8: | 1535 case MachineRepresentation::kWord8: |
| 1563 return opcode == kX64Cmp32 ? kX64Cmp8 : kX64Test8; | 1536 return opcode == kX64Cmp32 ? kX64Cmp8 : kX64Test8; |
| 1564 case MachineRepresentation::kWord16: | 1537 case MachineRepresentation::kWord16: |
| 1565 return opcode == kX64Cmp32 ? kX64Cmp16 : kX64Test16; | 1538 return opcode == kX64Cmp32 ? kX64Cmp16 : kX64Test16; |
| 1566 default: | 1539 default: |
| 1567 return opcode; | 1540 return opcode; |
| 1568 } | 1541 } |
| 1569 } | 1542 } |
| 1570 | 1543 |
| 1571 // Shared routine for multiple word compare operations. | 1544 // Shared routine for multiple word compare operations. |
| 1572 void VisitWordCompare(InstructionSelector* selector, Node* node, | 1545 void VisitWordCompare(InstructionSelector* selector, Node* node, |
| 1573 InstructionCode opcode, FlagsContinuation* cont) { | 1546 InstructionCode opcode, FlagsContinuation* cont) { |
| 1574 X64OperandGenerator g(selector); | 1547 X64OperandGenerator g(selector); |
| 1575 Node* left = node->InputAt(0); | 1548 Node* left = node->InputAt(0); |
| 1576 Node* right = node->InputAt(1); | 1549 Node* right = node->InputAt(1); |
| 1577 | 1550 |
| 1578 InstructionCode narrowed_opcode = TryNarrowOpcodeSize(opcode, left, right); | 1551 opcode = TryNarrowOpcodeSize(opcode, left, right); |
| 1579 | 1552 |
| 1580 // If one of the two inputs is an immediate, make sure it's on the right, or | 1553 // If one of the two inputs is an immediate, make sure it's on the right, or |
| 1581 // if one of the two inputs is a memory operand, make sure it's on the left. | 1554 // if one of the two inputs is a memory operand, make sure it's on the left. |
| 1555 int effect_level = selector->GetEffectLevel(node); |
| 1556 if (cont->IsBranch()) { |
| 1557 effect_level = selector->GetEffectLevel( |
| 1558 cont->true_block()->PredecessorAt(0)->control_input()); |
| 1559 } |
| 1560 |
| 1582 if ((!g.CanBeImmediate(right) && g.CanBeImmediate(left)) || | 1561 if ((!g.CanBeImmediate(right) && g.CanBeImmediate(left)) || |
| 1583 (g.CanBeMemoryOperand(narrowed_opcode, node, right) && | 1562 (g.CanBeMemoryOperand(opcode, node, right, effect_level) && |
| 1584 !g.CanBeMemoryOperand(narrowed_opcode, node, left))) { | 1563 !g.CanBeMemoryOperand(opcode, node, left, effect_level))) { |
| 1585 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); | 1564 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); |
| 1586 std::swap(left, right); | 1565 std::swap(left, right); |
| 1587 } | 1566 } |
| 1588 | 1567 |
| 1589 // Match immediates on right side of comparison. | 1568 // Match immediates on right side of comparison. |
| 1590 if (g.CanBeImmediate(right)) { | 1569 if (g.CanBeImmediate(right)) { |
| 1591 if (g.CanBeMemoryOperand(narrowed_opcode, node, left)) { | 1570 if (g.CanBeMemoryOperand(opcode, node, left, effect_level)) { |
| 1592 // If we're truncating the immediate (32 bits to 16 or 8), comparison | 1571 return VisitCompareWithMemoryOperand(selector, opcode, left, |
| 1593 // semantics should take the signedness/unsignedness of the op into | |
| 1594 // account. | |
| 1595 if (narrowed_opcode != opcode && | |
| 1596 LoadRepresentationOf(left->op()).IsUnsigned()) { | |
| 1597 switch (cont->condition()) { | |
| 1598 case FlagsCondition::kSignedLessThan: | |
| 1599 cont->OverwriteAndNegateIfEqual(FlagsCondition::kUnsignedLessThan); | |
| 1600 break; | |
| 1601 case FlagsCondition::kSignedGreaterThan: | |
| 1602 cont->OverwriteAndNegateIfEqual( | |
| 1603 FlagsCondition::kUnsignedGreaterThan); | |
| 1604 break; | |
| 1605 case FlagsCondition::kSignedLessThanOrEqual: | |
| 1606 cont->OverwriteAndNegateIfEqual( | |
| 1607 FlagsCondition::kUnsignedLessThanOrEqual); | |
| 1608 break; | |
| 1609 case FlagsCondition::kSignedGreaterThanOrEqual: | |
| 1610 cont->OverwriteAndNegateIfEqual( | |
| 1611 FlagsCondition::kUnsignedGreaterThanOrEqual); | |
| 1612 break; | |
| 1613 default: | |
| 1614 break; | |
| 1615 } | |
| 1616 } | |
| 1617 return VisitCompareWithMemoryOperand(selector, narrowed_opcode, left, | |
| 1618 g.UseImmediate(right), cont); | 1572 g.UseImmediate(right), cont); |
| 1619 } | 1573 } |
| 1620 return VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), | 1574 return VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), |
| 1621 cont); | 1575 cont); |
| 1622 } | 1576 } |
| 1623 | 1577 |
| 1624 // Match memory operands on left side of comparison. | 1578 // Match memory operands on left side of comparison. |
| 1625 if (g.CanBeMemoryOperand(narrowed_opcode, node, left)) { | 1579 if (g.CanBeMemoryOperand(opcode, node, left, effect_level)) { |
| 1626 return VisitCompareWithMemoryOperand(selector, narrowed_opcode, left, | 1580 return VisitCompareWithMemoryOperand(selector, opcode, left, |
| 1627 g.UseRegister(right), cont); | 1581 g.UseRegister(right), cont); |
| 1628 } | 1582 } |
| 1629 | 1583 |
| 1630 if (g.CanBeBetterLeftOperand(right)) { | 1584 if (g.CanBeBetterLeftOperand(right)) { |
| 1631 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); | 1585 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); |
| 1632 std::swap(left, right); | 1586 std::swap(left, right); |
| 1633 } | 1587 } |
| 1634 | 1588 |
| 1635 return VisitCompare(selector, opcode, left, right, cont, | 1589 return VisitCompare(selector, opcode, left, right, cont, |
| 1636 node->op()->HasProperty(Operator::kCommutative)); | 1590 node->op()->HasProperty(Operator::kCommutative)); |
| (...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2152 MachineOperatorBuilder::kFloat64RoundTruncate | | 2106 MachineOperatorBuilder::kFloat64RoundTruncate | |
| 2153 MachineOperatorBuilder::kFloat32RoundTiesEven | | 2107 MachineOperatorBuilder::kFloat32RoundTiesEven | |
| 2154 MachineOperatorBuilder::kFloat64RoundTiesEven; | 2108 MachineOperatorBuilder::kFloat64RoundTiesEven; |
| 2155 } | 2109 } |
| 2156 return flags; | 2110 return flags; |
| 2157 } | 2111 } |
| 2158 | 2112 |
| 2159 } // namespace compiler | 2113 } // namespace compiler |
| 2160 } // namespace internal | 2114 } // namespace internal |
| 2161 } // namespace v8 | 2115 } // namespace v8 |
| OLD | NEW |