OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/lithium-allocator-inl.h" | 7 #include "src/lithium-allocator-inl.h" |
8 #include "src/arm/lithium-arm.h" | 8 #include "src/arm/lithium-arm.h" |
9 #include "src/arm/lithium-codegen-arm.h" | 9 #include "src/arm/lithium-codegen-arm.h" |
10 #include "src/hydrogen-osr.h" | 10 #include "src/hydrogen-osr.h" |
(...skipping 658 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
669 UNREACHABLE(); | 669 UNREACHABLE(); |
670 return NULL; | 670 return NULL; |
671 } | 671 } |
672 | 672 |
673 | 673 |
674 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) { | 674 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) { |
675 return AssignEnvironment(new(zone()) LDeoptimize); | 675 return AssignEnvironment(new(zone()) LDeoptimize); |
676 } | 676 } |
677 | 677 |
678 | 678 |
| 679 HBitwiseBinaryOperation* LChunkBuilder::CanTransformToShiftedOp(HValue* val, |
| 680 HValue** left) { |
| 681 if (!val->representation().IsInteger32()) return NULL; |
| 682 if (!(val->IsBitwise() || val->IsAdd() || val->IsSub())) return NULL; |
| 683 |
| 684 HBinaryOperation* hinstr = HBinaryOperation::cast(val); |
| 685 HValue* hleft = hinstr->left(); |
| 686 HValue* hright = hinstr->right(); |
| 687 ASSERT(hleft->representation().Equals(hinstr->representation())); |
| 688 ASSERT(hright->representation().Equals(hinstr->representation())); |
| 689 |
| 690 if ((hright->IsConstant() && |
| 691 LikelyFitsImmField(hinstr, HConstant::cast(hright)->Integer32Value())) || |
| 692 (hinstr->IsCommutative() && hleft->IsConstant() && |
| 693 LikelyFitsImmField(hinstr, HConstant::cast(hleft)->Integer32Value()))) { |
| 694 // The constant operand will likely fit in the immediate field. We are |
| 695 // better off with |
| 696 // mov r1, r2 LSL #imm |
| 697 // add r0, r1, #imm2 |
| 698 // than with |
| 699 // mov r5, #imm2 |
| 700 // add r0, r5, r2 LSL #imm |
| 701 return NULL; |
| 702 } |
| 703 |
| 704 HBitwiseBinaryOperation* shift = NULL; |
| 705 // TODO(aleram): We will miss situations where a shift operation is used by |
| 706 // different instructions both as a left and right operands. |
| 707 if (hright->IsBitwiseBinaryShift() && |
| 708 HBitwiseBinaryOperation::cast(hright)->right()->IsConstant()) { |
| 709 shift = HBitwiseBinaryOperation::cast(hright); |
| 710 if (left != NULL) { |
| 711 *left = hleft; |
| 712 } |
| 713 } else if (hinstr->IsCommutative() && |
| 714 hleft->IsBitwiseBinaryShift() && |
| 715 HBitwiseBinaryOperation::cast(hleft)->right()->IsConstant()) { |
| 716 shift = HBitwiseBinaryOperation::cast(hleft); |
| 717 if (left != NULL) { |
| 718 *left = hright; |
| 719 } |
| 720 } else { |
| 721 return NULL; |
| 722 } |
| 723 |
| 724 if ((JSShiftAmountFromHConstant(shift->right()) == 0) && shift->IsShr()) { |
| 725 // Logical shifts right by zero can deoptimize. |
| 726 return NULL; |
| 727 } |
| 728 |
| 729 return shift; |
| 730 } |
| 731 |
| 732 |
| 733 bool LChunkBuilder::ShiftCanBeOptimizedAway(HBitwiseBinaryOperation* shift) { |
| 734 if (!shift->representation().IsInteger32()) { |
| 735 return false; |
| 736 } |
| 737 for (HUseIterator it(shift->uses()); !it.Done(); it.Advance()) { |
| 738 if (shift != CanTransformToShiftedOp(it.value())) { |
| 739 return false; |
| 740 } |
| 741 } |
| 742 return true; |
| 743 } |
| 744 |
| 745 |
| 746 LInstruction* LChunkBuilder::TryDoOpWithShiftedRightOperand( |
| 747 HBinaryOperation* instr) { |
| 748 HValue* left; |
| 749 HBitwiseBinaryOperation* shift = CanTransformToShiftedOp(instr, &left); |
| 750 |
| 751 if ((shift != NULL) && ShiftCanBeOptimizedAway(shift)) { |
| 752 return DoShiftedBinaryOp(instr, left, shift); |
| 753 } |
| 754 return NULL; |
| 755 } |
| 756 |
| 757 |
| 758 LInstruction* LChunkBuilder::DoShiftedBinaryOp( |
| 759 HBinaryOperation* hinstr, HValue* hleft, HBitwiseBinaryOperation* hshift) { |
| 760 ASSERT(hshift->IsBitwiseBinaryShift()); |
| 761 ASSERT(!hshift->IsShr() || (JSShiftAmountFromHConstant(hshift->right()) > 0)); |
| 762 |
| 763 LTemplateResultInstruction<1>* res; |
| 764 LOperand* left = UseRegisterAtStart(hleft); |
| 765 LOperand* right = UseRegisterAtStart(hshift->left()); |
| 766 LOperand* shift_amount = UseConstant(hshift->right()); |
| 767 ShiftOp shift_op; |
| 768 switch (hshift->opcode()) { |
| 769 case HValue::kShl: shift_op = LSL; break; |
| 770 case HValue::kShr: shift_op = LSR; break; |
| 771 case HValue::kSar: shift_op = ASR; break; |
| 772 default: UNREACHABLE(); shift_op = NO_SHIFT; |
| 773 } |
| 774 |
| 775 if (hinstr->IsBitwise()) { |
| 776 res = new(zone()) LBitI(left, right, shift_op, shift_amount); |
| 777 } else if (hinstr->IsAdd()) { |
| 778 res = new(zone()) LAddI(left, right, shift_op, shift_amount); |
| 779 } else { |
| 780 ASSERT(hinstr->IsSub()); |
| 781 res = new(zone()) LSubI(left, right, shift_op, shift_amount); |
| 782 } |
| 783 if (hinstr->CheckFlag(HValue::kCanOverflow)) { |
| 784 AssignEnvironment(res); |
| 785 } |
| 786 return DefineAsRegister(res); |
| 787 } |
| 788 |
| 789 |
679 LInstruction* LChunkBuilder::DoShift(Token::Value op, | 790 LInstruction* LChunkBuilder::DoShift(Token::Value op, |
680 HBitwiseBinaryOperation* instr) { | 791 HBitwiseBinaryOperation* instr) { |
681 if (instr->representation().IsSmiOrInteger32()) { | 792 if (instr->representation().IsSmiOrInteger32()) { |
682 ASSERT(instr->left()->representation().Equals(instr->representation())); | 793 ASSERT(instr->left()->representation().Equals(instr->representation())); |
683 ASSERT(instr->right()->representation().Equals(instr->representation())); | 794 ASSERT(instr->right()->representation().Equals(instr->representation())); |
| 795 |
| 796 if (ShiftCanBeOptimizedAway(instr)) { |
| 797 return NULL; |
| 798 } |
| 799 |
684 LOperand* left = UseRegisterAtStart(instr->left()); | 800 LOperand* left = UseRegisterAtStart(instr->left()); |
685 | 801 |
686 HValue* right_value = instr->right(); | 802 HValue* right_value = instr->right(); |
687 LOperand* right = NULL; | 803 LOperand* right = NULL; |
688 int constant_value = 0; | 804 int constant_value = 0; |
689 bool does_deopt = false; | 805 bool does_deopt = false; |
690 if (right_value->IsConstant()) { | 806 if (right_value->IsConstant()) { |
691 HConstant* constant = HConstant::cast(right_value); | 807 HConstant* constant = HConstant::cast(right_value); |
692 right = chunk_->DefineConstantOperand(constant); | 808 right = chunk_->DefineConstantOperand(constant); |
693 constant_value = constant->Integer32Value() & 0x1f; | 809 constant_value = JSShiftAmountFromHConstant(constant); |
694 // Left shifts can deoptimize if we shift by > 0 and the result cannot be | 810 // Left shifts can deoptimize if we shift by > 0 and the result cannot be |
695 // truncated to smi. | 811 // truncated to smi. |
696 if (instr->representation().IsSmi() && constant_value > 0) { | 812 if (instr->representation().IsSmi() && constant_value > 0) { |
697 does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi); | 813 does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi); |
698 } | 814 } |
699 } else { | 815 } else { |
700 right = UseRegisterAtStart(right_value); | 816 right = UseRegisterAtStart(right_value); |
701 } | 817 } |
702 | 818 |
703 // Shift operations can only deoptimize if we do a logical shift | 819 // Shift operations can only deoptimize if we do a logical shift |
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1243 return DoShift(Token::SHL, instr); | 1359 return DoShift(Token::SHL, instr); |
1244 } | 1360 } |
1245 | 1361 |
1246 | 1362 |
1247 LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { | 1363 LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { |
1248 if (instr->representation().IsSmiOrInteger32()) { | 1364 if (instr->representation().IsSmiOrInteger32()) { |
1249 ASSERT(instr->left()->representation().Equals(instr->representation())); | 1365 ASSERT(instr->left()->representation().Equals(instr->representation())); |
1250 ASSERT(instr->right()->representation().Equals(instr->representation())); | 1366 ASSERT(instr->right()->representation().Equals(instr->representation())); |
1251 ASSERT(instr->CheckFlag(HValue::kTruncatingToInt32)); | 1367 ASSERT(instr->CheckFlag(HValue::kTruncatingToInt32)); |
1252 | 1368 |
| 1369 LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr); |
| 1370 if (shifted_operation != NULL) { |
| 1371 return shifted_operation; |
| 1372 } |
| 1373 |
1253 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); | 1374 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); |
1254 LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand()); | 1375 LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand()); |
1255 return DefineAsRegister(new(zone()) LBitI(left, right)); | 1376 return DefineAsRegister(new(zone()) LBitI(left, right)); |
1256 } else { | 1377 } else { |
1257 return DoArithmeticT(instr->op(), instr); | 1378 return DoArithmeticT(instr->op(), instr); |
1258 } | 1379 } |
1259 } | 1380 } |
1260 | 1381 |
1261 | 1382 |
1262 LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) { | 1383 LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) { |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1526 return DoArithmeticT(Token::MUL, instr); | 1647 return DoArithmeticT(Token::MUL, instr); |
1527 } | 1648 } |
1528 } | 1649 } |
1529 | 1650 |
1530 | 1651 |
1531 LInstruction* LChunkBuilder::DoSub(HSub* instr) { | 1652 LInstruction* LChunkBuilder::DoSub(HSub* instr) { |
1532 if (instr->representation().IsSmiOrInteger32()) { | 1653 if (instr->representation().IsSmiOrInteger32()) { |
1533 ASSERT(instr->left()->representation().Equals(instr->representation())); | 1654 ASSERT(instr->left()->representation().Equals(instr->representation())); |
1534 ASSERT(instr->right()->representation().Equals(instr->representation())); | 1655 ASSERT(instr->right()->representation().Equals(instr->representation())); |
1535 | 1656 |
| 1657 LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr); |
| 1658 if (shifted_operation != NULL) { |
| 1659 return shifted_operation; |
| 1660 } |
| 1661 |
1536 if (instr->left()->IsConstant()) { | 1662 if (instr->left()->IsConstant()) { |
1537 // If lhs is constant, do reverse subtraction instead. | 1663 // If lhs is constant, do reverse subtraction instead. |
1538 return DoRSub(instr); | 1664 return DoRSub(instr); |
1539 } | 1665 } |
1540 | 1666 |
1541 LOperand* left = UseRegisterAtStart(instr->left()); | 1667 LOperand* left = UseRegisterAtStart(instr->left()); |
1542 LOperand* right = UseOrConstantAtStart(instr->right()); | 1668 LOperand* right = UseOrConstantAtStart(instr->right()); |
1543 LSubI* sub = new(zone()) LSubI(left, right); | 1669 LSubI* sub = new(zone()) LSubI(left, right); |
1544 LInstruction* result = DefineAsRegister(sub); | 1670 LInstruction* result = DefineAsRegister(sub); |
1545 if (instr->CheckFlag(HValue::kCanOverflow)) { | 1671 if (instr->CheckFlag(HValue::kCanOverflow)) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1593 return DefineSameAsFirst(new(zone()) LMultiplySubD(minuend_op, | 1719 return DefineSameAsFirst(new(zone()) LMultiplySubD(minuend_op, |
1594 multiplier_op, | 1720 multiplier_op, |
1595 multiplicand_op)); | 1721 multiplicand_op)); |
1596 } | 1722 } |
1597 | 1723 |
1598 | 1724 |
1599 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { | 1725 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { |
1600 if (instr->representation().IsSmiOrInteger32()) { | 1726 if (instr->representation().IsSmiOrInteger32()) { |
1601 ASSERT(instr->left()->representation().Equals(instr->representation())); | 1727 ASSERT(instr->left()->representation().Equals(instr->representation())); |
1602 ASSERT(instr->right()->representation().Equals(instr->representation())); | 1728 ASSERT(instr->right()->representation().Equals(instr->representation())); |
| 1729 |
| 1730 LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr); |
| 1731 if (shifted_operation != NULL) { |
| 1732 return shifted_operation; |
| 1733 } |
| 1734 |
1603 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); | 1735 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); |
1604 LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand()); | 1736 LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand()); |
1605 LAddI* add = new(zone()) LAddI(left, right); | 1737 LAddI* add = new(zone()) LAddI(left, right); |
1606 LInstruction* result = DefineAsRegister(add); | 1738 LInstruction* result = DefineAsRegister(add); |
1607 if (instr->CheckFlag(HValue::kCanOverflow)) { | 1739 if (instr->CheckFlag(HValue::kCanOverflow)) { |
1608 result = AssignEnvironment(result); | 1740 result = AssignEnvironment(result); |
1609 } | 1741 } |
1610 return result; | 1742 return result; |
1611 } else if (instr->representation().IsExternal()) { | 1743 } else if (instr->representation().IsExternal()) { |
1612 ASSERT(instr->left()->representation().IsExternal()); | 1744 ASSERT(instr->left()->representation().IsExternal()); |
(...skipping 976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2589 LInstruction* LChunkBuilder::DoAllocateBlockContext( | 2721 LInstruction* LChunkBuilder::DoAllocateBlockContext( |
2590 HAllocateBlockContext* instr) { | 2722 HAllocateBlockContext* instr) { |
2591 LOperand* context = UseFixed(instr->context(), cp); | 2723 LOperand* context = UseFixed(instr->context(), cp); |
2592 LOperand* function = UseRegisterAtStart(instr->function()); | 2724 LOperand* function = UseRegisterAtStart(instr->function()); |
2593 LAllocateBlockContext* result = | 2725 LAllocateBlockContext* result = |
2594 new(zone()) LAllocateBlockContext(context, function); | 2726 new(zone()) LAllocateBlockContext(context, function); |
2595 return MarkAsCall(DefineFixed(result, cp), instr); | 2727 return MarkAsCall(DefineFixed(result, cp), instr); |
2596 } | 2728 } |
2597 | 2729 |
2598 } } // namespace v8::internal | 2730 } } // namespace v8::internal |
OLD | NEW |