Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Side by Side Diff: src/x64/code-stubs-x64.cc

Issue 6580032: X64 Crankshaft: Add untagged version of TranscendentalCacheStub to x64, enabl... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/code-stubs-x64.h ('k') | src/x64/codegen-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1488 matching lines...) Expand 10 before | Expand all | Expand 10 after
1499 1499
1500 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { 1500 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
1501 __ pop(rcx); 1501 __ pop(rcx);
1502 __ push(rdx); 1502 __ push(rdx);
1503 __ push(rax); 1503 __ push(rax);
1504 __ push(rcx); 1504 __ push(rcx);
1505 } 1505 }
1506 1506
1507 1507
1508 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { 1508 void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
1509 // Input on stack: 1509 // TAGGED case:
1510 // rsp[8]: argument (should be number). 1510 // Input:
1511 // rsp[0]: return address. 1511 // rsp[8]: argument (should be number).
1512 // rsp[0]: return address.
1513 // Output:
1514 // rax: tagged double result.
1515 // UNTAGGED case:
1516 // Input::
1517 // rsp[0]: return address.
1518 // xmm1: untagged double input argument
1519 // Output:
1520 // xmm1: untagged double result.
1521
1512 Label runtime_call; 1522 Label runtime_call;
1513 Label runtime_call_clear_stack; 1523 Label runtime_call_clear_stack;
1514 Label input_not_smi; 1524 Label skip_cache;
1515 NearLabel loaded; 1525 const bool tagged = (argument_type_ == TAGGED);
1516 // Test that rax is a number. 1526 if (tagged) {
1517 __ movq(rax, Operand(rsp, kPointerSize)); 1527 NearLabel input_not_smi;
1518 __ JumpIfNotSmi(rax, &input_not_smi); 1528 NearLabel loaded;
1519 // Input is a smi. Untag and load it onto the FPU stack. 1529 // Test that rax is a number.
1520 // Then load the bits of the double into rbx. 1530 __ movq(rax, Operand(rsp, kPointerSize));
1521 __ SmiToInteger32(rax, rax); 1531 __ JumpIfNotSmi(rax, &input_not_smi);
1522 __ subq(rsp, Immediate(kPointerSize)); 1532 // Input is a smi. Untag and load it onto the FPU stack.
1523 __ cvtlsi2sd(xmm1, rax); 1533 // Then load the bits of the double into rbx.
1524 __ movsd(Operand(rsp, 0), xmm1); 1534 __ SmiToInteger32(rax, rax);
1525 __ movq(rbx, xmm1); 1535 __ subq(rsp, Immediate(kDoubleSize));
1526 __ movq(rdx, xmm1); 1536 __ cvtlsi2sd(xmm1, rax);
1527 __ fld_d(Operand(rsp, 0)); 1537 __ movsd(Operand(rsp, 0), xmm1);
1528 __ addq(rsp, Immediate(kPointerSize)); 1538 __ movq(rbx, xmm1);
1529 __ jmp(&loaded); 1539 __ movq(rdx, xmm1);
1540 __ fld_d(Operand(rsp, 0));
1541 __ addq(rsp, Immediate(kDoubleSize));
1542 __ jmp(&loaded);
1530 1543
1531 __ bind(&input_not_smi); 1544 __ bind(&input_not_smi);
1532 // Check if input is a HeapNumber. 1545 // Check if input is a HeapNumber.
1533 __ Move(rbx, Factory::heap_number_map()); 1546 __ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex);
1534 __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); 1547 __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
1535 __ j(not_equal, &runtime_call); 1548 __ j(not_equal, &runtime_call);
1536 // Input is a HeapNumber. Push it on the FPU stack and load its 1549 // Input is a HeapNumber. Push it on the FPU stack and load its
1537 // bits into rbx. 1550 // bits into rbx.
1538 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); 1551 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
1539 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); 1552 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
1540 __ movq(rdx, rbx); 1553 __ movq(rdx, rbx);
1541 __ bind(&loaded); 1554
1542 // ST[0] == double value 1555 __ bind(&loaded);
1556 } else { // UNTAGGED.
1557 __ movq(rbx, xmm1);
1558 __ movq(rdx, xmm1);
1559 }
1560
1561 // ST[0] == double value, if TAGGED.
1543 // rbx = bits of double value. 1562 // rbx = bits of double value.
1544 // rdx = also bits of double value. 1563 // rdx = also bits of double value.
1545 // Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic): 1564 // Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic):
1546 // h = h0 = bits ^ (bits >> 32); 1565 // h = h0 = bits ^ (bits >> 32);
1547 // h ^= h >> 16; 1566 // h ^= h >> 16;
1548 // h ^= h >> 8; 1567 // h ^= h >> 8;
1549 // h = h & (cacheSize - 1); 1568 // h = h & (cacheSize - 1);
1550 // or h = (h0 ^ (h0 >> 8) ^ (h0 >> 16) ^ (h0 >> 24)) & (cacheSize - 1) 1569 // or h = (h0 ^ (h0 >> 8) ^ (h0 >> 16) ^ (h0 >> 24)) & (cacheSize - 1)
1551 __ sar(rdx, Immediate(32)); 1570 __ sar(rdx, Immediate(32));
1552 __ xorl(rdx, rbx); 1571 __ xorl(rdx, rbx);
(...skipping 11 matching lines...) Expand all
1564 1583
1565 // ST[0] == double value. 1584 // ST[0] == double value.
1566 // rbx = bits of double value. 1585 // rbx = bits of double value.
1567 // rcx = TranscendentalCache::hash(double value). 1586 // rcx = TranscendentalCache::hash(double value).
1568 __ movq(rax, ExternalReference::transcendental_cache_array_address()); 1587 __ movq(rax, ExternalReference::transcendental_cache_array_address());
1569 // rax points to cache array. 1588 // rax points to cache array.
1570 __ movq(rax, Operand(rax, type_ * sizeof(TranscendentalCache::caches_[0]))); 1589 __ movq(rax, Operand(rax, type_ * sizeof(TranscendentalCache::caches_[0])));
1571 // rax points to the cache for the type type_. 1590 // rax points to the cache for the type type_.
1572 // If NULL, the cache hasn't been initialized yet, so go through runtime. 1591 // If NULL, the cache hasn't been initialized yet, so go through runtime.
1573 __ testq(rax, rax); 1592 __ testq(rax, rax);
1574 __ j(zero, &runtime_call_clear_stack); 1593 __ j(zero, &runtime_call_clear_stack); // Only clears stack if TAGGED.
1575 #ifdef DEBUG 1594 #ifdef DEBUG
1576 // Check that the layout of cache elements match expectations. 1595 // Check that the layout of cache elements match expectations.
1577 { // NOLINT - doesn't like a single brace on a line. 1596 { // NOLINT - doesn't like a single brace on a line.
1578 TranscendentalCache::Element test_elem[2]; 1597 TranscendentalCache::Element test_elem[2];
1579 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 1598 char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
1580 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 1599 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
1581 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 1600 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
1582 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 1601 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
1583 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 1602 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
1584 // Two uint_32's and a pointer per element. 1603 // Two uint_32's and a pointer per element.
1585 CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); 1604 CHECK_EQ(16, static_cast<int>(elem2_start - elem_start));
1586 CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); 1605 CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start));
1587 CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); 1606 CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start));
1588 CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); 1607 CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start));
1589 } 1608 }
1590 #endif 1609 #endif
1591 // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. 1610 // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16].
1592 __ addl(rcx, rcx); 1611 __ addl(rcx, rcx);
1593 __ lea(rcx, Operand(rax, rcx, times_8, 0)); 1612 __ lea(rcx, Operand(rax, rcx, times_8, 0));
1594 // Check if cache matches: Double value is stored in uint32_t[2] array. 1613 // Check if cache matches: Double value is stored in uint32_t[2] array.
1595 NearLabel cache_miss; 1614 NearLabel cache_miss;
1596 __ cmpq(rbx, Operand(rcx, 0)); 1615 __ cmpq(rbx, Operand(rcx, 0));
1597 __ j(not_equal, &cache_miss); 1616 __ j(not_equal, &cache_miss);
1598 // Cache hit! 1617 // Cache hit!
1599 __ movq(rax, Operand(rcx, 2 * kIntSize)); 1618 __ movq(rax, Operand(rcx, 2 * kIntSize));
1600 __ fstp(0); // Clear FPU stack. 1619 if (tagged) {
1601 __ ret(kPointerSize); 1620 __ fstp(0); // Clear FPU stack.
1621 __ ret(kPointerSize);
1622 } else { // UNTAGGED.
1623 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1624 __ Ret();
1625 }
1602 1626
1603 __ bind(&cache_miss); 1627 __ bind(&cache_miss);
1604 // Update cache with new value. 1628 // Update cache with new value.
1605 Label nan_result; 1629 if (tagged) {
1606 GenerateOperation(masm, &nan_result);
1607 __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack); 1630 __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack);
1631 } else { // UNTAGGED.
1632 __ AllocateHeapNumber(rax, rdi, &skip_cache);
1633 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
1634 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
1635 }
1636 GenerateOperation(masm);
1608 __ movq(Operand(rcx, 0), rbx); 1637 __ movq(Operand(rcx, 0), rbx);
1609 __ movq(Operand(rcx, 2 * kIntSize), rax); 1638 __ movq(Operand(rcx, 2 * kIntSize), rax);
1610 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); 1639 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
1611 __ ret(kPointerSize); 1640 if (tagged) {
1641 __ ret(kPointerSize);
1642 } else { // UNTAGGED.
1643 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1644 __ Ret();
1612 1645
1613 __ bind(&runtime_call_clear_stack); 1646 // Skip cache and return answer directly, only in untagged case.
1614 __ fstp(0); 1647 __ bind(&skip_cache);
1615 __ bind(&runtime_call); 1648 __ subq(rsp, Immediate(kDoubleSize));
1616 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); 1649 __ movsd(Operand(rsp, 0), xmm1);
1650 __ fld_d(Operand(rsp, 0));
1651 GenerateOperation(masm);
1652 __ fstp_d(Operand(rsp, 0));
1653 __ movsd(xmm1, Operand(rsp, 0));
1654 __ addq(rsp, Immediate(kDoubleSize));
1655 // We return the value in xmm1 without adding it to the cache, but
1656 // we cause a scavenging GC so that future allocations will succeed.
1657 __ EnterInternalFrame();
1658 // Allocate an unused object bigger than a HeapNumber.
1659 __ Push(Smi::FromInt(2 * kDoubleSize));
1660 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
1661 __ LeaveInternalFrame();
1662 __ Ret();
1663 }
1617 1664
1618 __ bind(&nan_result); 1665 // Call runtime, doing whatever allocation and cleanup is necessary.
1619 __ fstp(0); // Remove argument from FPU stack. 1666 if (tagged) {
1620 __ LoadRoot(rax, Heap::kNanValueRootIndex); 1667 __ bind(&runtime_call_clear_stack);
1621 __ movq(Operand(rcx, 0), rbx); 1668 __ fstp(0);
1622 __ movq(Operand(rcx, 2 * kIntSize), rax); 1669 __ bind(&runtime_call);
1623 __ ret(kPointerSize); 1670 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
1671 } else { // UNTAGGED.
1672 __ bind(&runtime_call_clear_stack);
1673 __ bind(&runtime_call);
1674 __ AllocateHeapNumber(rax, rdi, &skip_cache);
1675 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
1676 __ EnterInternalFrame();
1677 __ push(rax);
1678 __ CallRuntime(RuntimeFunction(), 1);
1679 __ LeaveInternalFrame();
1680 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1681 __ Ret();
1682 }
1624 } 1683 }
1625 1684
1626 1685
1627 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { 1686 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
1628 switch (type_) { 1687 switch (type_) {
1629 // Add more cases when necessary. 1688 // Add more cases when necessary.
1630 case TranscendentalCache::SIN: return Runtime::kMath_sin; 1689 case TranscendentalCache::SIN: return Runtime::kMath_sin;
1631 case TranscendentalCache::COS: return Runtime::kMath_cos; 1690 case TranscendentalCache::COS: return Runtime::kMath_cos;
1632 case TranscendentalCache::LOG: return Runtime::kMath_log; 1691 case TranscendentalCache::LOG: return Runtime::kMath_log;
1633 default: 1692 default:
1634 UNIMPLEMENTED(); 1693 UNIMPLEMENTED();
1635 return Runtime::kAbort; 1694 return Runtime::kAbort;
1636 } 1695 }
1637 } 1696 }
1638 1697
1639 1698
1640 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm, 1699 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
1641 Label* on_nan_result) {
1642 // Registers: 1700 // Registers:
1701 // rax: Newly allocated HeapNumber, which must be preserved.
1643 // rbx: Bits of input double. Must be preserved. 1702 // rbx: Bits of input double. Must be preserved.
1644 // rcx: Pointer to cache entry. Must be preserved. 1703 // rcx: Pointer to cache entry. Must be preserved.
1645 // st(0): Input double 1704 // st(0): Input double
1646 Label done; 1705 Label done;
1647 if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { 1706 if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) {
1648 // Both fsin and fcos require arguments in the range +/-2^63 and 1707 // Both fsin and fcos require arguments in the range +/-2^63 and
1649 // return NaN for infinities and NaN. They can share all code except 1708 // return NaN for infinities and NaN. They can share all code except
1650 // the actual fsin/fcos operation. 1709 // the actual fsin/fcos operation.
1651 Label in_range; 1710 Label in_range;
1652 // If argument is outside the range -2^63..2^63, fsin/cos doesn't 1711 // If argument is outside the range -2^63..2^63, fsin/cos doesn't
1653 // work. We must reduce it to the appropriate range. 1712 // work. We must reduce it to the appropriate range.
1654 __ movq(rdi, rbx); 1713 __ movq(rdi, rbx);
1655 // Move exponent and sign bits to low bits. 1714 // Move exponent and sign bits to low bits.
1656 __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); 1715 __ shr(rdi, Immediate(HeapNumber::kMantissaBits));
1657 // Remove sign bit. 1716 // Remove sign bit.
1658 __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); 1717 __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1));
1659 int supported_exponent_limit = (63 + HeapNumber::kExponentBias); 1718 int supported_exponent_limit = (63 + HeapNumber::kExponentBias);
1660 __ cmpl(rdi, Immediate(supported_exponent_limit)); 1719 __ cmpl(rdi, Immediate(supported_exponent_limit));
1661 __ j(below, &in_range); 1720 __ j(below, &in_range);
1662 // Check for infinity and NaN. Both return NaN for sin. 1721 // Check for infinity and NaN. Both return NaN for sin.
1663 __ cmpl(rdi, Immediate(0x7ff)); 1722 __ cmpl(rdi, Immediate(0x7ff));
1664 __ j(equal, on_nan_result); 1723 NearLabel non_nan_result;
1724 __ j(not_equal, &non_nan_result);
1725 // Input is +/-Infinity or NaN. Result is NaN.
1726 __ fstp(0);
1727 __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex);
1728 __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset));
1729 __ jmp(&done);
1730
1731 __ bind(&non_nan_result);
1665 1732
1666 // Use fpmod to restrict argument to the range +/-2*PI. 1733 // Use fpmod to restrict argument to the range +/-2*PI.
1734 __ movq(rdi, rax); // Save rax before using fnstsw_ax.
1667 __ fldpi(); 1735 __ fldpi();
1668 __ fadd(0); 1736 __ fadd(0);
1669 __ fld(1); 1737 __ fld(1);
1670 // FPU Stack: input, 2*pi, input. 1738 // FPU Stack: input, 2*pi, input.
1671 { 1739 {
1672 Label no_exceptions; 1740 Label no_exceptions;
1673 __ fwait(); 1741 __ fwait();
1674 __ fnstsw_ax(); 1742 __ fnstsw_ax();
1675 // Clear if Illegal Operand or Zero Division exceptions are set. 1743 // Clear if Illegal Operand or Zero Division exceptions are set.
1676 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. 1744 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word.
(...skipping 12 matching lines...) Expand all
1689 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. 1757 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word.
1690 // If C2 is set, computation only has partial result. Loop to 1758 // If C2 is set, computation only has partial result. Loop to
1691 // continue computation. 1759 // continue computation.
1692 __ j(not_zero, &partial_remainder_loop); 1760 __ j(not_zero, &partial_remainder_loop);
1693 } 1761 }
1694 // FPU Stack: input, 2*pi, input % 2*pi 1762 // FPU Stack: input, 2*pi, input % 2*pi
1695 __ fstp(2); 1763 __ fstp(2);
1696 // FPU Stack: input % 2*pi, 2*pi, 1764 // FPU Stack: input % 2*pi, 2*pi,
1697 __ fstp(0); 1765 __ fstp(0);
1698 // FPU Stack: input % 2*pi 1766 // FPU Stack: input % 2*pi
1767 __ movq(rax, rdi); // Restore rax, pointer to the new HeapNumber.
1699 __ bind(&in_range); 1768 __ bind(&in_range);
1700 switch (type_) { 1769 switch (type_) {
1701 case TranscendentalCache::SIN: 1770 case TranscendentalCache::SIN:
1702 __ fsin(); 1771 __ fsin();
1703 break; 1772 break;
1704 case TranscendentalCache::COS: 1773 case TranscendentalCache::COS:
1705 __ fcos(); 1774 __ fcos();
1706 break; 1775 break;
1707 default: 1776 default:
1708 UNREACHABLE(); 1777 UNREACHABLE();
(...skipping 3157 matching lines...) Expand 10 before | Expand all | Expand 10 after
4866 FieldOperand(elements, PixelArray::kExternalPointerOffset)); 4935 FieldOperand(elements, PixelArray::kExternalPointerOffset));
4867 __ movb(Operand(external_pointer, untagged_key, times_1, 0), untagged_value); 4936 __ movb(Operand(external_pointer, untagged_key, times_1, 0), untagged_value);
4868 __ ret(0); // Return value in eax. 4937 __ ret(0); // Return value in eax.
4869 } 4938 }
4870 4939
4871 #undef __ 4940 #undef __
4872 4941
4873 } } // namespace v8::internal 4942 } } // namespace v8::internal
4874 4943
4875 #endif // V8_TARGET_ARCH_X64 4944 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/code-stubs-x64.h ('k') | src/x64/codegen-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698