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 = constant->Integer32Value() & 0x1f; |
ulan
2014/06/10 11:53:37
Use JSShiftAmountFromHConstant?
Alexandre Rames
2014/06/11 10:19:40
Done.
| |
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 960 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2573 | 2705 |
2574 LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) { | 2706 LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) { |
2575 LOperand* object = UseRegister(instr->object()); | 2707 LOperand* object = UseRegister(instr->object()); |
2576 LOperand* index = UseTempRegister(instr->index()); | 2708 LOperand* index = UseTempRegister(instr->index()); |
2577 LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index); | 2709 LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index); |
2578 LInstruction* result = DefineSameAsFirst(load); | 2710 LInstruction* result = DefineSameAsFirst(load); |
2579 return AssignPointerMap(result); | 2711 return AssignPointerMap(result); |
2580 } | 2712 } |
2581 | 2713 |
2582 } } // namespace v8::internal | 2714 } } // namespace v8::internal |
OLD | NEW |