OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 #if V8_TARGET_ARCH_X64 | 7 #if V8_TARGET_ARCH_X64 |
8 | 8 |
9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
(...skipping 1274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1285 // Check for (kMinInt / -1). | 1285 // Check for (kMinInt / -1). |
1286 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) { | 1286 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) { |
1287 __ cmpl(dividend, Immediate(kMinInt)); | 1287 __ cmpl(dividend, Immediate(kMinInt)); |
1288 DeoptimizeIf(zero, instr, "overflow"); | 1288 DeoptimizeIf(zero, instr, "overflow"); |
1289 } | 1289 } |
1290 // Deoptimize if remainder will not be 0. | 1290 // Deoptimize if remainder will not be 0. |
1291 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && | 1291 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && |
1292 divisor != 1 && divisor != -1) { | 1292 divisor != 1 && divisor != -1) { |
1293 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); | 1293 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); |
1294 __ testl(dividend, Immediate(mask)); | 1294 __ testl(dividend, Immediate(mask)); |
1295 DeoptimizeIf(not_zero, instr, "remainder not zero"); | 1295 DeoptimizeIf(not_zero, instr, "lost precision"); |
1296 } | 1296 } |
1297 __ Move(result, dividend); | 1297 __ Move(result, dividend); |
1298 int32_t shift = WhichPowerOf2Abs(divisor); | 1298 int32_t shift = WhichPowerOf2Abs(divisor); |
1299 if (shift > 0) { | 1299 if (shift > 0) { |
1300 // The arithmetic shift is always OK, the 'if' is an optimization only. | 1300 // The arithmetic shift is always OK, the 'if' is an optimization only. |
1301 if (shift > 1) __ sarl(result, Immediate(31)); | 1301 if (shift > 1) __ sarl(result, Immediate(31)); |
1302 __ shrl(result, Immediate(32 - shift)); | 1302 __ shrl(result, Immediate(32 - shift)); |
1303 __ addl(result, dividend); | 1303 __ addl(result, dividend); |
1304 __ sarl(result, Immediate(shift)); | 1304 __ sarl(result, Immediate(shift)); |
1305 } | 1305 } |
(...skipping 18 matching lines...) Expand all Loading... |
1324 DeoptimizeIf(zero, instr, "minus zero"); | 1324 DeoptimizeIf(zero, instr, "minus zero"); |
1325 } | 1325 } |
1326 | 1326 |
1327 __ TruncatingDiv(dividend, Abs(divisor)); | 1327 __ TruncatingDiv(dividend, Abs(divisor)); |
1328 if (divisor < 0) __ negl(rdx); | 1328 if (divisor < 0) __ negl(rdx); |
1329 | 1329 |
1330 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { | 1330 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { |
1331 __ movl(rax, rdx); | 1331 __ movl(rax, rdx); |
1332 __ imull(rax, rax, Immediate(divisor)); | 1332 __ imull(rax, rax, Immediate(divisor)); |
1333 __ subl(rax, dividend); | 1333 __ subl(rax, dividend); |
1334 DeoptimizeIf(not_equal, instr, "remainder not zero"); | 1334 DeoptimizeIf(not_equal, instr, "lost precision"); |
1335 } | 1335 } |
1336 } | 1336 } |
1337 | 1337 |
1338 | 1338 |
1339 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI. | 1339 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI. |
1340 void LCodeGen::DoDivI(LDivI* instr) { | 1340 void LCodeGen::DoDivI(LDivI* instr) { |
1341 HBinaryOperation* hdiv = instr->hydrogen(); | 1341 HBinaryOperation* hdiv = instr->hydrogen(); |
1342 Register dividend = ToRegister(instr->dividend()); | 1342 Register dividend = ToRegister(instr->dividend()); |
1343 Register divisor = ToRegister(instr->divisor()); | 1343 Register divisor = ToRegister(instr->divisor()); |
1344 Register remainder = ToRegister(instr->temp()); | 1344 Register remainder = ToRegister(instr->temp()); |
(...skipping 29 matching lines...) Expand all Loading... |
1374 __ bind(÷nd_not_min_int); | 1374 __ bind(÷nd_not_min_int); |
1375 } | 1375 } |
1376 | 1376 |
1377 // Sign extend to rdx (= remainder). | 1377 // Sign extend to rdx (= remainder). |
1378 __ cdq(); | 1378 __ cdq(); |
1379 __ idivl(divisor); | 1379 __ idivl(divisor); |
1380 | 1380 |
1381 if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { | 1381 if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { |
1382 // Deoptimize if remainder is not 0. | 1382 // Deoptimize if remainder is not 0. |
1383 __ testl(remainder, remainder); | 1383 __ testl(remainder, remainder); |
1384 DeoptimizeIf(not_zero, instr, "remainder not zero"); | 1384 DeoptimizeIf(not_zero, instr, "lost precision"); |
1385 } | 1385 } |
1386 } | 1386 } |
1387 | 1387 |
1388 | 1388 |
1389 void LCodeGen::DoMulI(LMulI* instr) { | 1389 void LCodeGen::DoMulI(LMulI* instr) { |
1390 Register left = ToRegister(instr->left()); | 1390 Register left = ToRegister(instr->left()); |
1391 LOperand* right = instr->right(); | 1391 LOperand* right = instr->right(); |
1392 | 1392 |
1393 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1393 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
1394 if (instr->hydrogen_value()->representation().IsSmi()) { | 1394 if (instr->hydrogen_value()->representation().IsSmi()) { |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1602 case Token::ROR: | 1602 case Token::ROR: |
1603 __ rorl_cl(ToRegister(left)); | 1603 __ rorl_cl(ToRegister(left)); |
1604 break; | 1604 break; |
1605 case Token::SAR: | 1605 case Token::SAR: |
1606 __ sarl_cl(ToRegister(left)); | 1606 __ sarl_cl(ToRegister(left)); |
1607 break; | 1607 break; |
1608 case Token::SHR: | 1608 case Token::SHR: |
1609 __ shrl_cl(ToRegister(left)); | 1609 __ shrl_cl(ToRegister(left)); |
1610 if (instr->can_deopt()) { | 1610 if (instr->can_deopt()) { |
1611 __ testl(ToRegister(left), ToRegister(left)); | 1611 __ testl(ToRegister(left), ToRegister(left)); |
1612 DeoptimizeIf(negative, instr, "value to shift was negative"); | 1612 DeoptimizeIf(negative, instr, "negative value"); |
1613 } | 1613 } |
1614 break; | 1614 break; |
1615 case Token::SHL: | 1615 case Token::SHL: |
1616 __ shll_cl(ToRegister(left)); | 1616 __ shll_cl(ToRegister(left)); |
1617 break; | 1617 break; |
1618 default: | 1618 default: |
1619 UNREACHABLE(); | 1619 UNREACHABLE(); |
1620 break; | 1620 break; |
1621 } | 1621 } |
1622 } else { | 1622 } else { |
1623 int32_t value = ToInteger32(LConstantOperand::cast(right)); | 1623 int32_t value = ToInteger32(LConstantOperand::cast(right)); |
1624 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); | 1624 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); |
1625 switch (instr->op()) { | 1625 switch (instr->op()) { |
1626 case Token::ROR: | 1626 case Token::ROR: |
1627 if (shift_count != 0) { | 1627 if (shift_count != 0) { |
1628 __ rorl(ToRegister(left), Immediate(shift_count)); | 1628 __ rorl(ToRegister(left), Immediate(shift_count)); |
1629 } | 1629 } |
1630 break; | 1630 break; |
1631 case Token::SAR: | 1631 case Token::SAR: |
1632 if (shift_count != 0) { | 1632 if (shift_count != 0) { |
1633 __ sarl(ToRegister(left), Immediate(shift_count)); | 1633 __ sarl(ToRegister(left), Immediate(shift_count)); |
1634 } | 1634 } |
1635 break; | 1635 break; |
1636 case Token::SHR: | 1636 case Token::SHR: |
1637 if (shift_count != 0) { | 1637 if (shift_count != 0) { |
1638 __ shrl(ToRegister(left), Immediate(shift_count)); | 1638 __ shrl(ToRegister(left), Immediate(shift_count)); |
1639 } else if (instr->can_deopt()) { | 1639 } else if (instr->can_deopt()) { |
1640 __ testl(ToRegister(left), ToRegister(left)); | 1640 __ testl(ToRegister(left), ToRegister(left)); |
1641 DeoptimizeIf(negative, instr, "value to shift was negative"); | 1641 DeoptimizeIf(negative, instr, "negative value"); |
1642 } | 1642 } |
1643 break; | 1643 break; |
1644 case Token::SHL: | 1644 case Token::SHL: |
1645 if (shift_count != 0) { | 1645 if (shift_count != 0) { |
1646 if (instr->hydrogen_value()->representation().IsSmi()) { | 1646 if (instr->hydrogen_value()->representation().IsSmi()) { |
1647 if (SmiValuesAre32Bits()) { | 1647 if (SmiValuesAre32Bits()) { |
1648 __ shlp(ToRegister(left), Immediate(shift_count)); | 1648 __ shlp(ToRegister(left), Immediate(shift_count)); |
1649 } else { | 1649 } else { |
1650 DCHECK(SmiValuesAre31Bits()); | 1650 DCHECK(SmiValuesAre31Bits()); |
1651 if (instr->can_deopt()) { | 1651 if (instr->can_deopt()) { |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1754 | 1754 |
1755 void LCodeGen::DoDateField(LDateField* instr) { | 1755 void LCodeGen::DoDateField(LDateField* instr) { |
1756 Register object = ToRegister(instr->date()); | 1756 Register object = ToRegister(instr->date()); |
1757 Register result = ToRegister(instr->result()); | 1757 Register result = ToRegister(instr->result()); |
1758 Smi* index = instr->index(); | 1758 Smi* index = instr->index(); |
1759 Label runtime, done, not_date_object; | 1759 Label runtime, done, not_date_object; |
1760 DCHECK(object.is(result)); | 1760 DCHECK(object.is(result)); |
1761 DCHECK(object.is(rax)); | 1761 DCHECK(object.is(rax)); |
1762 | 1762 |
1763 Condition cc = masm()->CheckSmi(object); | 1763 Condition cc = masm()->CheckSmi(object); |
1764 DeoptimizeIf(cc, instr, "not an object"); | 1764 DeoptimizeIf(cc, instr, "Smi"); |
1765 __ CmpObjectType(object, JS_DATE_TYPE, kScratchRegister); | 1765 __ CmpObjectType(object, JS_DATE_TYPE, kScratchRegister); |
1766 DeoptimizeIf(not_equal, instr, "not a date object"); | 1766 DeoptimizeIf(not_equal, instr, "not a date object"); |
1767 | 1767 |
1768 if (index->value() == 0) { | 1768 if (index->value() == 0) { |
1769 __ movp(result, FieldOperand(object, JSDate::kValueOffset)); | 1769 __ movp(result, FieldOperand(object, JSDate::kValueOffset)); |
1770 } else { | 1770 } else { |
1771 if (index->value() < JSDate::kFirstUncachedField) { | 1771 if (index->value() < JSDate::kFirstUncachedField) { |
1772 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); | 1772 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); |
1773 Operand stamp_operand = __ ExternalOperand(stamp); | 1773 Operand stamp_operand = __ ExternalOperand(stamp); |
1774 __ movp(kScratchRegister, stamp_operand); | 1774 __ movp(kScratchRegister, stamp_operand); |
(...skipping 1606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3381 } | 3381 } |
3382 | 3382 |
3383 // Normal function. Replace undefined or null with global receiver. | 3383 // Normal function. Replace undefined or null with global receiver. |
3384 __ CompareRoot(receiver, Heap::kNullValueRootIndex); | 3384 __ CompareRoot(receiver, Heap::kNullValueRootIndex); |
3385 __ j(equal, &global_object, Label::kNear); | 3385 __ j(equal, &global_object, Label::kNear); |
3386 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex); | 3386 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex); |
3387 __ j(equal, &global_object, Label::kNear); | 3387 __ j(equal, &global_object, Label::kNear); |
3388 | 3388 |
3389 // The receiver should be a JS object. | 3389 // The receiver should be a JS object. |
3390 Condition is_smi = __ CheckSmi(receiver); | 3390 Condition is_smi = __ CheckSmi(receiver); |
3391 DeoptimizeIf(is_smi, instr, "not an object"); | 3391 DeoptimizeIf(is_smi, instr, "Smi"); |
3392 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); | 3392 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); |
3393 DeoptimizeIf(below, instr, "not a spec object"); | 3393 DeoptimizeIf(below, instr, "not a JavaScript object"); |
3394 | 3394 |
3395 __ jmp(&receiver_ok, Label::kNear); | 3395 __ jmp(&receiver_ok, Label::kNear); |
3396 __ bind(&global_object); | 3396 __ bind(&global_object); |
3397 __ movp(receiver, FieldOperand(function, JSFunction::kContextOffset)); | 3397 __ movp(receiver, FieldOperand(function, JSFunction::kContextOffset)); |
3398 __ movp(receiver, | 3398 __ movp(receiver, |
3399 Operand(receiver, | 3399 Operand(receiver, |
3400 Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | 3400 Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
3401 __ movp(receiver, FieldOperand(receiver, GlobalObject::kGlobalProxyOffset)); | 3401 __ movp(receiver, FieldOperand(receiver, GlobalObject::kGlobalProxyOffset)); |
3402 | 3402 |
3403 __ bind(&receiver_ok); | 3403 __ bind(&receiver_ok); |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3728 } | 3728 } |
3729 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown); | 3729 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown); |
3730 __ cvttsd2si(output_reg, xmm_scratch); | 3730 __ cvttsd2si(output_reg, xmm_scratch); |
3731 __ cmpl(output_reg, Immediate(0x1)); | 3731 __ cmpl(output_reg, Immediate(0x1)); |
3732 DeoptimizeIf(overflow, instr, "overflow"); | 3732 DeoptimizeIf(overflow, instr, "overflow"); |
3733 } else { | 3733 } else { |
3734 Label negative_sign, done; | 3734 Label negative_sign, done; |
3735 // Deoptimize on unordered. | 3735 // Deoptimize on unordered. |
3736 __ xorps(xmm_scratch, xmm_scratch); // Zero the register. | 3736 __ xorps(xmm_scratch, xmm_scratch); // Zero the register. |
3737 __ ucomisd(input_reg, xmm_scratch); | 3737 __ ucomisd(input_reg, xmm_scratch); |
3738 DeoptimizeIf(parity_even, instr, "unordered"); | 3738 DeoptimizeIf(parity_even, instr, "NaN"); |
3739 __ j(below, &negative_sign, Label::kNear); | 3739 __ j(below, &negative_sign, Label::kNear); |
3740 | 3740 |
3741 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 3741 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
3742 // Check for negative zero. | 3742 // Check for negative zero. |
3743 Label positive_sign; | 3743 Label positive_sign; |
3744 __ j(above, &positive_sign, Label::kNear); | 3744 __ j(above, &positive_sign, Label::kNear); |
3745 __ movmskpd(output_reg, input_reg); | 3745 __ movmskpd(output_reg, input_reg); |
3746 __ testq(output_reg, Immediate(1)); | 3746 __ testq(output_reg, Immediate(1)); |
3747 DeoptimizeIf(not_zero, instr, "minus zero"); | 3747 DeoptimizeIf(not_zero, instr, "minus zero"); |
3748 __ Set(output_reg, 0); | 3748 __ Set(output_reg, 0); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3785 __ movq(kScratchRegister, one_half); | 3785 __ movq(kScratchRegister, one_half); |
3786 __ movq(xmm_scratch, kScratchRegister); | 3786 __ movq(xmm_scratch, kScratchRegister); |
3787 __ ucomisd(xmm_scratch, input_reg); | 3787 __ ucomisd(xmm_scratch, input_reg); |
3788 __ j(above, &below_one_half, Label::kNear); | 3788 __ j(above, &below_one_half, Label::kNear); |
3789 | 3789 |
3790 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x). | 3790 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x). |
3791 __ addsd(xmm_scratch, input_reg); | 3791 __ addsd(xmm_scratch, input_reg); |
3792 __ cvttsd2si(output_reg, xmm_scratch); | 3792 __ cvttsd2si(output_reg, xmm_scratch); |
3793 // Overflow is signalled with minint. | 3793 // Overflow is signalled with minint. |
3794 __ cmpl(output_reg, Immediate(0x1)); | 3794 __ cmpl(output_reg, Immediate(0x1)); |
3795 DeoptimizeIf(overflow, instr, "conversion overflow"); | 3795 DeoptimizeIf(overflow, instr, "overflow"); |
3796 __ jmp(&done, dist); | 3796 __ jmp(&done, dist); |
3797 | 3797 |
3798 __ bind(&below_one_half); | 3798 __ bind(&below_one_half); |
3799 __ movq(kScratchRegister, minus_one_half); | 3799 __ movq(kScratchRegister, minus_one_half); |
3800 __ movq(xmm_scratch, kScratchRegister); | 3800 __ movq(xmm_scratch, kScratchRegister); |
3801 __ ucomisd(xmm_scratch, input_reg); | 3801 __ ucomisd(xmm_scratch, input_reg); |
3802 __ j(below_equal, &round_to_zero, Label::kNear); | 3802 __ j(below_equal, &round_to_zero, Label::kNear); |
3803 | 3803 |
3804 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then | 3804 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then |
3805 // compare and compensate. | 3805 // compare and compensate. |
3806 __ movq(input_temp, input_reg); // Do not alter input_reg. | 3806 __ movq(input_temp, input_reg); // Do not alter input_reg. |
3807 __ subsd(input_temp, xmm_scratch); | 3807 __ subsd(input_temp, xmm_scratch); |
3808 __ cvttsd2si(output_reg, input_temp); | 3808 __ cvttsd2si(output_reg, input_temp); |
3809 // Catch minint due to overflow, and to prevent overflow when compensating. | 3809 // Catch minint due to overflow, and to prevent overflow when compensating. |
3810 __ cmpl(output_reg, Immediate(0x1)); | 3810 __ cmpl(output_reg, Immediate(0x1)); |
3811 DeoptimizeIf(overflow, instr, "conversion overflow"); | 3811 DeoptimizeIf(overflow, instr, "overflow"); |
3812 | 3812 |
3813 __ Cvtlsi2sd(xmm_scratch, output_reg); | 3813 __ Cvtlsi2sd(xmm_scratch, output_reg); |
3814 __ ucomisd(xmm_scratch, input_temp); | 3814 __ ucomisd(xmm_scratch, input_temp); |
3815 __ j(equal, &done, dist); | 3815 __ j(equal, &done, dist); |
3816 __ subl(output_reg, Immediate(1)); | 3816 __ subl(output_reg, Immediate(1)); |
3817 // No overflow because we already ruled out minint. | 3817 // No overflow because we already ruled out minint. |
3818 __ jmp(&done, dist); | 3818 __ jmp(&done, dist); |
3819 | 3819 |
3820 __ bind(&round_to_zero); | 3820 __ bind(&round_to_zero); |
3821 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if | 3821 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if |
(...skipping 1012 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4834 } | 4834 } |
4835 | 4835 |
4836 | 4836 |
4837 void LCodeGen::DoSmiTag(LSmiTag* instr) { | 4837 void LCodeGen::DoSmiTag(LSmiTag* instr) { |
4838 HChange* hchange = instr->hydrogen(); | 4838 HChange* hchange = instr->hydrogen(); |
4839 Register input = ToRegister(instr->value()); | 4839 Register input = ToRegister(instr->value()); |
4840 Register output = ToRegister(instr->result()); | 4840 Register output = ToRegister(instr->result()); |
4841 if (hchange->CheckFlag(HValue::kCanOverflow) && | 4841 if (hchange->CheckFlag(HValue::kCanOverflow) && |
4842 hchange->value()->CheckFlag(HValue::kUint32)) { | 4842 hchange->value()->CheckFlag(HValue::kUint32)) { |
4843 Condition is_smi = __ CheckUInteger32ValidSmiValue(input); | 4843 Condition is_smi = __ CheckUInteger32ValidSmiValue(input); |
4844 DeoptimizeIf(NegateCondition(is_smi), instr, "not a smi"); | 4844 DeoptimizeIf(NegateCondition(is_smi), instr, "overflow"); |
4845 } | 4845 } |
4846 __ Integer32ToSmi(output, input); | 4846 __ Integer32ToSmi(output, input); |
4847 if (hchange->CheckFlag(HValue::kCanOverflow) && | 4847 if (hchange->CheckFlag(HValue::kCanOverflow) && |
4848 !hchange->value()->CheckFlag(HValue::kUint32)) { | 4848 !hchange->value()->CheckFlag(HValue::kUint32)) { |
4849 DeoptimizeIf(overflow, instr, "overflow"); | 4849 DeoptimizeIf(overflow, instr, "overflow"); |
4850 } | 4850 } |
4851 } | 4851 } |
4852 | 4852 |
4853 | 4853 |
4854 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { | 4854 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { |
4855 DCHECK(instr->value()->Equals(instr->result())); | 4855 DCHECK(instr->value()->Equals(instr->result())); |
4856 Register input = ToRegister(instr->value()); | 4856 Register input = ToRegister(instr->value()); |
4857 if (instr->needs_check()) { | 4857 if (instr->needs_check()) { |
4858 Condition is_smi = __ CheckSmi(input); | 4858 Condition is_smi = __ CheckSmi(input); |
4859 DeoptimizeIf(NegateCondition(is_smi), instr, "not a smi"); | 4859 DeoptimizeIf(NegateCondition(is_smi), instr, "not a Smi"); |
4860 } else { | 4860 } else { |
4861 __ AssertSmi(input); | 4861 __ AssertSmi(input); |
4862 } | 4862 } |
4863 __ SmiToInteger32(input, input); | 4863 __ SmiToInteger32(input, input); |
4864 } | 4864 } |
4865 | 4865 |
4866 | 4866 |
4867 void LCodeGen::EmitNumberUntagD(LNumberUntagD* instr, Register input_reg, | 4867 void LCodeGen::EmitNumberUntagD(LNumberUntagD* instr, Register input_reg, |
4868 XMMRegister result_reg, NumberUntagDMode mode) { | 4868 XMMRegister result_reg, NumberUntagDMode mode) { |
4869 bool can_convert_undefined_to_nan = | 4869 bool can_convert_undefined_to_nan = |
(...skipping 29 matching lines...) Expand all Loading... |
4899 __ testq(kScratchRegister, Immediate(1)); | 4899 __ testq(kScratchRegister, Immediate(1)); |
4900 DeoptimizeIf(not_zero, instr, "minus zero"); | 4900 DeoptimizeIf(not_zero, instr, "minus zero"); |
4901 } | 4901 } |
4902 __ jmp(&done, Label::kNear); | 4902 __ jmp(&done, Label::kNear); |
4903 | 4903 |
4904 if (can_convert_undefined_to_nan) { | 4904 if (can_convert_undefined_to_nan) { |
4905 __ bind(&convert); | 4905 __ bind(&convert); |
4906 | 4906 |
4907 // Convert undefined (and hole) to NaN. Compute NaN as 0/0. | 4907 // Convert undefined (and hole) to NaN. Compute NaN as 0/0. |
4908 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex); | 4908 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex); |
4909 DeoptimizeIf(not_equal, instr, "neither a heap number nor undefined"); | 4909 DeoptimizeIf(not_equal, instr, "not a heap number/undefined"); |
4910 | 4910 |
4911 __ xorps(result_reg, result_reg); | 4911 __ xorps(result_reg, result_reg); |
4912 __ divsd(result_reg, result_reg); | 4912 __ divsd(result_reg, result_reg); |
4913 __ jmp(&done, Label::kNear); | 4913 __ jmp(&done, Label::kNear); |
4914 } | 4914 } |
4915 } else { | 4915 } else { |
4916 DCHECK(mode == NUMBER_CANDIDATE_IS_SMI); | 4916 DCHECK(mode == NUMBER_CANDIDATE_IS_SMI); |
4917 } | 4917 } |
4918 | 4918 |
4919 // Smi to XMM conversion | 4919 // Smi to XMM conversion |
(...skipping 26 matching lines...) Expand all Loading... |
4946 __ jmp(done); | 4946 __ jmp(done); |
4947 | 4947 |
4948 __ bind(&check_bools); | 4948 __ bind(&check_bools); |
4949 __ CompareRoot(input_reg, Heap::kTrueValueRootIndex); | 4949 __ CompareRoot(input_reg, Heap::kTrueValueRootIndex); |
4950 __ j(not_equal, &check_false, Label::kNear); | 4950 __ j(not_equal, &check_false, Label::kNear); |
4951 __ Set(input_reg, 1); | 4951 __ Set(input_reg, 1); |
4952 __ jmp(done); | 4952 __ jmp(done); |
4953 | 4953 |
4954 __ bind(&check_false); | 4954 __ bind(&check_false); |
4955 __ CompareRoot(input_reg, Heap::kFalseValueRootIndex); | 4955 __ CompareRoot(input_reg, Heap::kFalseValueRootIndex); |
4956 DeoptimizeIf(not_equal, instr, "cannot truncate"); | 4956 DeoptimizeIf(not_equal, instr, "not a heap number/undefined/true/false"); |
4957 __ Set(input_reg, 0); | 4957 __ Set(input_reg, 0); |
4958 } else { | 4958 } else { |
4959 XMMRegister scratch = ToDoubleRegister(instr->temp()); | 4959 XMMRegister scratch = ToDoubleRegister(instr->temp()); |
4960 DCHECK(!scratch.is(xmm0)); | 4960 DCHECK(!scratch.is(xmm0)); |
4961 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), | 4961 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), |
4962 Heap::kHeapNumberMapRootIndex); | 4962 Heap::kHeapNumberMapRootIndex); |
4963 DeoptimizeIf(not_equal, instr, "not a heap number"); | 4963 DeoptimizeIf(not_equal, instr, "not a heap number"); |
4964 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 4964 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
4965 __ cvttsd2si(input_reg, xmm0); | 4965 __ cvttsd2si(input_reg, xmm0); |
4966 __ Cvtlsi2sd(scratch, input_reg); | 4966 __ Cvtlsi2sd(scratch, input_reg); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5029 DCHECK(input->IsDoubleRegister()); | 5029 DCHECK(input->IsDoubleRegister()); |
5030 LOperand* result = instr->result(); | 5030 LOperand* result = instr->result(); |
5031 DCHECK(result->IsRegister()); | 5031 DCHECK(result->IsRegister()); |
5032 | 5032 |
5033 XMMRegister input_reg = ToDoubleRegister(input); | 5033 XMMRegister input_reg = ToDoubleRegister(input); |
5034 Register result_reg = ToRegister(result); | 5034 Register result_reg = ToRegister(result); |
5035 | 5035 |
5036 if (instr->truncating()) { | 5036 if (instr->truncating()) { |
5037 __ TruncateDoubleToI(result_reg, input_reg); | 5037 __ TruncateDoubleToI(result_reg, input_reg); |
5038 } else { | 5038 } else { |
5039 Label bailout, done; | 5039 Label lost_precision, is_nan, minus_zero, done; |
5040 XMMRegister xmm_scratch = double_scratch0(); | 5040 XMMRegister xmm_scratch = double_scratch0(); |
5041 __ DoubleToI(result_reg, input_reg, xmm_scratch, | 5041 __ DoubleToI(result_reg, input_reg, xmm_scratch, |
5042 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear); | 5042 instr->hydrogen()->GetMinusZeroMode(), &lost_precision, |
5043 | 5043 &is_nan, &minus_zero, |
| 5044 DeoptEveryNTimes() ? Label::kFar : Label::kNear); |
5044 __ jmp(&done, Label::kNear); | 5045 __ jmp(&done, Label::kNear); |
5045 __ bind(&bailout); | 5046 __ bind(&lost_precision); |
5046 DeoptimizeIf(no_condition, instr, "conversion failed"); | 5047 DeoptimizeIf(no_condition, instr, "lost precision"); |
| 5048 __ bind(&is_nan); |
| 5049 DeoptimizeIf(no_condition, instr, "NaN"); |
| 5050 __ bind(&minus_zero); |
| 5051 DeoptimizeIf(no_condition, instr, "minus zero"); |
5047 __ bind(&done); | 5052 __ bind(&done); |
5048 } | 5053 } |
5049 } | 5054 } |
5050 | 5055 |
5051 | 5056 |
5052 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { | 5057 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { |
5053 LOperand* input = instr->value(); | 5058 LOperand* input = instr->value(); |
5054 DCHECK(input->IsDoubleRegister()); | 5059 DCHECK(input->IsDoubleRegister()); |
5055 LOperand* result = instr->result(); | 5060 LOperand* result = instr->result(); |
5056 DCHECK(result->IsRegister()); | 5061 DCHECK(result->IsRegister()); |
5057 | 5062 |
5058 XMMRegister input_reg = ToDoubleRegister(input); | 5063 XMMRegister input_reg = ToDoubleRegister(input); |
5059 Register result_reg = ToRegister(result); | 5064 Register result_reg = ToRegister(result); |
5060 | 5065 |
5061 Label bailout, done; | 5066 Label lost_precision, is_nan, minus_zero, done; |
5062 XMMRegister xmm_scratch = double_scratch0(); | 5067 XMMRegister xmm_scratch = double_scratch0(); |
5063 __ DoubleToI(result_reg, input_reg, xmm_scratch, | 5068 __ DoubleToI(result_reg, input_reg, xmm_scratch, |
5064 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear); | 5069 instr->hydrogen()->GetMinusZeroMode(), &lost_precision, &is_nan, |
5065 | 5070 &minus_zero, DeoptEveryNTimes() ? Label::kFar : Label::kNear); |
5066 __ jmp(&done, Label::kNear); | 5071 __ jmp(&done, Label::kNear); |
5067 __ bind(&bailout); | 5072 __ bind(&lost_precision); |
5068 DeoptimizeIf(no_condition, instr, "conversion failed"); | 5073 DeoptimizeIf(no_condition, instr, "lost precision"); |
| 5074 __ bind(&is_nan); |
| 5075 DeoptimizeIf(no_condition, instr, "NaN"); |
| 5076 __ bind(&minus_zero); |
| 5077 DeoptimizeIf(no_condition, instr, "minus zero"); |
5069 __ bind(&done); | 5078 __ bind(&done); |
5070 | |
5071 __ Integer32ToSmi(result_reg, result_reg); | 5079 __ Integer32ToSmi(result_reg, result_reg); |
5072 DeoptimizeIf(overflow, instr, "overflow"); | 5080 DeoptimizeIf(overflow, instr, "overflow"); |
5073 } | 5081 } |
5074 | 5082 |
5075 | 5083 |
5076 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 5084 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
5077 LOperand* input = instr->value(); | 5085 LOperand* input = instr->value(); |
5078 Condition cc = masm()->CheckSmi(ToRegister(input)); | 5086 Condition cc = masm()->CheckSmi(ToRegister(input)); |
5079 DeoptimizeIf(NegateCondition(cc), instr, "not a Smi"); | 5087 DeoptimizeIf(NegateCondition(cc), instr, "not a Smi"); |
5080 } | 5088 } |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5238 __ JumpIfSmi(input_reg, &is_smi, dist); | 5246 __ JumpIfSmi(input_reg, &is_smi, dist); |
5239 | 5247 |
5240 // Check for heap number | 5248 // Check for heap number |
5241 __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 5249 __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
5242 factory()->heap_number_map()); | 5250 factory()->heap_number_map()); |
5243 __ j(equal, &heap_number, Label::kNear); | 5251 __ j(equal, &heap_number, Label::kNear); |
5244 | 5252 |
5245 // Check for undefined. Undefined is converted to zero for clamping | 5253 // Check for undefined. Undefined is converted to zero for clamping |
5246 // conversions. | 5254 // conversions. |
5247 __ Cmp(input_reg, factory()->undefined_value()); | 5255 __ Cmp(input_reg, factory()->undefined_value()); |
5248 DeoptimizeIf(not_equal, instr, "neither a heap number nor undefined"); | 5256 DeoptimizeIf(not_equal, instr, "not a heap number/undefined"); |
5249 __ xorl(input_reg, input_reg); | 5257 __ xorl(input_reg, input_reg); |
5250 __ jmp(&done, Label::kNear); | 5258 __ jmp(&done, Label::kNear); |
5251 | 5259 |
5252 // Heap number | 5260 // Heap number |
5253 __ bind(&heap_number); | 5261 __ bind(&heap_number); |
5254 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 5262 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
5255 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg); | 5263 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg); |
5256 __ jmp(&done, Label::kNear); | 5264 __ jmp(&done, Label::kNear); |
5257 | 5265 |
5258 // smi | 5266 // smi |
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5746 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 5754 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
5747 __ jmp(&use_cache, Label::kNear); | 5755 __ jmp(&use_cache, Label::kNear); |
5748 | 5756 |
5749 // Get the set of properties to enumerate. | 5757 // Get the set of properties to enumerate. |
5750 __ bind(&call_runtime); | 5758 __ bind(&call_runtime); |
5751 __ Push(rax); | 5759 __ Push(rax); |
5752 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr); | 5760 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr); |
5753 | 5761 |
5754 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 5762 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
5755 Heap::kMetaMapRootIndex); | 5763 Heap::kMetaMapRootIndex); |
5756 DeoptimizeIf(not_equal, instr, "not a meta map"); | 5764 DeoptimizeIf(not_equal, instr, "wrong map"); |
5757 __ bind(&use_cache); | 5765 __ bind(&use_cache); |
5758 } | 5766 } |
5759 | 5767 |
5760 | 5768 |
5761 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { | 5769 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { |
5762 Register map = ToRegister(instr->map()); | 5770 Register map = ToRegister(instr->map()); |
5763 Register result = ToRegister(instr->result()); | 5771 Register result = ToRegister(instr->result()); |
5764 Label load_cache, done; | 5772 Label load_cache, done; |
5765 __ EnumLength(result, map); | 5773 __ EnumLength(result, map); |
5766 __ Cmp(result, Smi::FromInt(0)); | 5774 __ Cmp(result, Smi::FromInt(0)); |
5767 __ j(not_equal, &load_cache, Label::kNear); | 5775 __ j(not_equal, &load_cache, Label::kNear); |
5768 __ LoadRoot(result, Heap::kEmptyFixedArrayRootIndex); | 5776 __ LoadRoot(result, Heap::kEmptyFixedArrayRootIndex); |
5769 __ jmp(&done, Label::kNear); | 5777 __ jmp(&done, Label::kNear); |
5770 __ bind(&load_cache); | 5778 __ bind(&load_cache); |
5771 __ LoadInstanceDescriptors(map, result); | 5779 __ LoadInstanceDescriptors(map, result); |
5772 __ movp(result, | 5780 __ movp(result, |
5773 FieldOperand(result, DescriptorArray::kEnumCacheOffset)); | 5781 FieldOperand(result, DescriptorArray::kEnumCacheOffset)); |
5774 __ movp(result, | 5782 __ movp(result, |
5775 FieldOperand(result, FixedArray::SizeFor(instr->idx()))); | 5783 FieldOperand(result, FixedArray::SizeFor(instr->idx()))); |
5776 __ bind(&done); | 5784 __ bind(&done); |
5777 Condition cc = masm()->CheckSmi(result); | 5785 Condition cc = masm()->CheckSmi(result); |
5778 DeoptimizeIf(cc, instr, "Smi"); | 5786 DeoptimizeIf(cc, instr, "no cache"); |
5779 } | 5787 } |
5780 | 5788 |
5781 | 5789 |
5782 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { | 5790 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { |
5783 Register object = ToRegister(instr->value()); | 5791 Register object = ToRegister(instr->value()); |
5784 __ cmpp(ToRegister(instr->map()), | 5792 __ cmpp(ToRegister(instr->map()), |
5785 FieldOperand(object, HeapObject::kMapOffset)); | 5793 FieldOperand(object, HeapObject::kMapOffset)); |
5786 DeoptimizeIf(not_equal, instr, "wrong map"); | 5794 DeoptimizeIf(not_equal, instr, "wrong map"); |
5787 } | 5795 } |
5788 | 5796 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5871 CallRuntime(Runtime::kPushBlockContext, 2, instr); | 5879 CallRuntime(Runtime::kPushBlockContext, 2, instr); |
5872 RecordSafepoint(Safepoint::kNoLazyDeopt); | 5880 RecordSafepoint(Safepoint::kNoLazyDeopt); |
5873 } | 5881 } |
5874 | 5882 |
5875 | 5883 |
5876 #undef __ | 5884 #undef __ |
5877 | 5885 |
5878 } } // namespace v8::internal | 5886 } } // namespace v8::internal |
5879 | 5887 |
5880 #endif // V8_TARGET_ARCH_X64 | 5888 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |