| 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 |