| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 1799 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1810 | 1810 |
| 1811 Register temp = locs()->temp(0).reg(); | 1811 Register temp = locs()->temp(0).reg(); |
| 1812 // Generate stack overflow check. | 1812 // Generate stack overflow check. |
| 1813 __ movq(temp, Immediate(Isolate::Current()->stack_limit_address())); | 1813 __ movq(temp, Immediate(Isolate::Current()->stack_limit_address())); |
| 1814 __ cmpq(RSP, Address(temp, 0)); | 1814 __ cmpq(RSP, Address(temp, 0)); |
| 1815 __ j(BELOW_EQUAL, slow_path->entry_label()); | 1815 __ j(BELOW_EQUAL, slow_path->entry_label()); |
| 1816 __ Bind(slow_path->exit_label()); | 1816 __ Bind(slow_path->exit_label()); |
| 1817 } | 1817 } |
| 1818 | 1818 |
| 1819 | 1819 |
| 1820 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 1821 BinarySmiOpInstr* shift_left) { |
| 1822 const bool is_truncating = shift_left->is_truncating(); |
| 1823 const LocationSummary& locs = *shift_left->locs(); |
| 1824 Register left = locs.in(0).reg(); |
| 1825 Register result = locs.out().reg(); |
| 1826 ASSERT(left == result); |
| 1827 Label* deopt = shift_left->CanDeoptimize() ? |
| 1828 compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL; |
| 1829 if (locs.in(1).IsConstant()) { |
| 1830 const Object& constant = locs.in(1).constant(); |
| 1831 ASSERT(constant.IsSmi()); |
| 1832 // shll operation masks the count to 6 bits. |
| 1833 const intptr_t kCountLimit = 0x3F; |
| 1834 const intptr_t value = Smi::Cast(constant).Value(); |
| 1835 if (value == 0) { |
| 1836 // No code needed. |
| 1837 } else if ((value < 0) || (value >= kCountLimit)) { |
| 1838 // This condition may not be known earlier in some cases because |
| 1839 // of constant propagation, inlining, etc. |
| 1840 if ((value >=kCountLimit) && is_truncating) { |
| 1841 __ xorq(result, result); |
| 1842 } else { |
| 1843 // Result is Mint or exception. |
| 1844 __ jmp(deopt); |
| 1845 } |
| 1846 } else { |
| 1847 if (is_truncating) { |
| 1848 __ shlq(left, Immediate(value)); |
| 1849 } else { |
| 1850 Register temp = locs.temp(0).reg(); |
| 1851 __ movq(temp, left); |
| 1852 __ shlq(left, Immediate(value)); |
| 1853 __ sarq(left, Immediate(value)); |
| 1854 __ cmpq(left, temp); |
| 1855 __ j(NOT_EQUAL, deopt); // Overflow. |
| 1856 // Shift for result now we know there is no overflow. |
| 1857 __ shlq(left, Immediate(value)); |
| 1858 } |
| 1859 } |
| 1860 return; |
| 1861 } |
| 1862 |
| 1863 // Right (locs.in(1)) is not constant. |
| 1864 Register right = locs.in(1).reg(); |
| 1865 Range* right_range = shift_left->right()->definition()->range(); |
| 1866 if (shift_left->left()->BindsToConstant() && !is_truncating) { |
| 1867 // TODO(srdjan): Implement code below for is_truncating(). |
| 1868 // If left is constant, we know the maximal allowed size for right. |
| 1869 const Object& obj = shift_left->left()->BoundConstant(); |
| 1870 if (obj.IsSmi()) { |
| 1871 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 1872 if (left_int == 0) { |
| 1873 __ cmpq(right, Immediate(0)); |
| 1874 __ j(NEGATIVE, deopt); |
| 1875 return; |
| 1876 } |
| 1877 intptr_t tmp = (left_int > 0) ? left_int : ~left_int; |
| 1878 intptr_t max_right = kSmiBits; |
| 1879 while ((tmp >>= 1) != 0) { |
| 1880 max_right--; |
| 1881 } |
| 1882 const bool right_needs_check = |
| 1883 (right_range == NULL) || |
| 1884 !right_range->IsWithin(0, max_right - 1); |
| 1885 if (right_needs_check) { |
| 1886 __ cmpq(right, |
| 1887 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right)))); |
| 1888 __ j(ABOVE_EQUAL, deopt); |
| 1889 } |
| 1890 __ SmiUntag(right); |
| 1891 __ shlq(left, right); |
| 1892 } |
| 1893 return; |
| 1894 } |
| 1895 |
| 1896 const bool right_needs_check = |
| 1897 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); |
| 1898 ASSERT(right == RCX); // Count must be in RCX |
| 1899 if (is_truncating) { |
| 1900 if (right_needs_check) { |
| 1901 const bool right_may_be_negative = |
| 1902 (right_range == NULL) || |
| 1903 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); |
| 1904 if (right_may_be_negative) { |
| 1905 ASSERT(shift_left->CanDeoptimize()); |
| 1906 __ cmpq(right, Immediate(0)); |
| 1907 __ j(NEGATIVE, deopt); |
| 1908 } |
| 1909 Label done, is_not_zero; |
| 1910 __ cmpq(right, |
| 1911 Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits)))); |
| 1912 __ j(BELOW, &is_not_zero, Assembler::kNearJump); |
| 1913 __ xorq(left, left); |
| 1914 __ jmp(&done, Assembler::kNearJump); |
| 1915 __ Bind(&is_not_zero); |
| 1916 __ SmiUntag(right); |
| 1917 __ shlq(left, right); |
| 1918 __ Bind(&done); |
| 1919 } else { |
| 1920 __ SmiUntag(right); |
| 1921 __ shlq(left, right); |
| 1922 } |
| 1923 } else { |
| 1924 if (right_needs_check) { |
| 1925 ASSERT(shift_left->CanDeoptimize()); |
| 1926 __ cmpq(right, |
| 1927 Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits)))); |
| 1928 __ j(ABOVE_EQUAL, deopt); |
| 1929 } |
| 1930 // Left is not a constant. |
| 1931 Register temp = locs.temp(0).reg(); |
| 1932 // Check if count too large for handling it inlined. |
| 1933 __ movq(temp, left); |
| 1934 __ SmiUntag(right); |
| 1935 // Overflow test (preserve temp and right); |
| 1936 __ shlq(left, right); |
| 1937 __ sarq(left, right); |
| 1938 __ cmpq(left, temp); |
| 1939 __ j(NOT_EQUAL, deopt); // Overflow. |
| 1940 // Shift for result now we know there is no overflow. |
| 1941 __ shlq(left, right); |
| 1942 } |
| 1943 } |
| 1944 |
| 1945 |
| 1820 static bool CanBeImmediate(const Object& constant) { | 1946 static bool CanBeImmediate(const Object& constant) { |
| 1821 return constant.IsSmi() && | 1947 return constant.IsSmi() && |
| 1822 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32(); | 1948 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32(); |
| 1823 } | 1949 } |
| 1824 | 1950 |
| 1825 | 1951 |
| 1826 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 1952 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| 1827 const intptr_t kNumInputs = 2; | 1953 const intptr_t kNumInputs = 2; |
| 1828 | 1954 |
| 1829 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 1955 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1862 return summary; | 1988 return summary; |
| 1863 } else if (op_kind() == Token::kSHR) { | 1989 } else if (op_kind() == Token::kSHR) { |
| 1864 const intptr_t kNumTemps = 0; | 1990 const intptr_t kNumTemps = 0; |
| 1865 LocationSummary* summary = | 1991 LocationSummary* summary = |
| 1866 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 1992 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 1867 summary->set_in(0, Location::RequiresRegister()); | 1993 summary->set_in(0, Location::RequiresRegister()); |
| 1868 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); | 1994 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); |
| 1869 summary->set_out(Location::SameAsFirstInput()); | 1995 summary->set_out(Location::SameAsFirstInput()); |
| 1870 return summary; | 1996 return summary; |
| 1871 } else if (op_kind() == Token::kSHL) { | 1997 } else if (op_kind() == Token::kSHL) { |
| 1872 const intptr_t kNumTemps = 1; | 1998 const intptr_t kNumTemps = is_truncating() ? 0 : 1; |
| 1873 LocationSummary* summary = | 1999 LocationSummary* summary = |
| 1874 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2000 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 1875 summary->set_in(0, Location::RequiresRegister()); | 2001 summary->set_in(0, Location::RequiresRegister()); |
| 1876 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); | 2002 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); |
| 1877 summary->set_temp(0, Location::RequiresRegister()); | 2003 if (!is_truncating()) { |
| 2004 summary->set_temp(0, Location::RequiresRegister()); |
| 2005 } |
| 1878 summary->set_out(Location::SameAsFirstInput()); | 2006 summary->set_out(Location::SameAsFirstInput()); |
| 1879 return summary; | 2007 return summary; |
| 1880 } else { | 2008 } else { |
| 1881 const intptr_t kNumTemps = 0; | 2009 const intptr_t kNumTemps = 0; |
| 1882 LocationSummary* summary = | 2010 LocationSummary* summary = |
| 1883 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2011 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 1884 summary->set_in(0, Location::RequiresRegister()); | 2012 summary->set_in(0, Location::RequiresRegister()); |
| 1885 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 2013 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 1886 summary->set_out(Location::SameAsFirstInput()); | 2014 summary->set_out(Location::SameAsFirstInput()); |
| 1887 return summary; | 2015 return summary; |
| 1888 } | 2016 } |
| 1889 } | 2017 } |
| 1890 | 2018 |
| 1891 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2019 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2020 if (op_kind() == Token::kSHL) { |
| 2021 EmitSmiShiftLeft(compiler, this); |
| 2022 return; |
| 2023 } |
| 2024 |
| 2025 ASSERT(!is_truncating()); |
| 1892 Register left = locs()->in(0).reg(); | 2026 Register left = locs()->in(0).reg(); |
| 1893 Register result = locs()->out().reg(); | 2027 Register result = locs()->out().reg(); |
| 1894 ASSERT(left == result); | 2028 ASSERT(left == result); |
| 1895 Label* deopt = NULL; | 2029 Label* deopt = NULL; |
| 1896 if (CanDeoptimize()) { | 2030 if (CanDeoptimize()) { |
| 1897 deopt = compiler->AddDeoptStub(deopt_id(), | 2031 deopt = compiler->AddDeoptStub(deopt_id(), |
| 1898 kDeoptBinarySmiOp); | 2032 kDeoptBinarySmiOp); |
| 1899 } | 2033 } |
| 1900 | 2034 |
| 1901 if (locs()->in(1).IsConstant()) { | 2035 if (locs()->in(1).IsConstant()) { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1983 break; | 2117 break; |
| 1984 } | 2118 } |
| 1985 | 2119 |
| 1986 value = value + kSmiTagSize; | 2120 value = value + kSmiTagSize; |
| 1987 if (value >= kCountLimit) value = kCountLimit; | 2121 if (value >= kCountLimit) value = kCountLimit; |
| 1988 | 2122 |
| 1989 __ sarq(left, Immediate(value)); | 2123 __ sarq(left, Immediate(value)); |
| 1990 __ SmiTag(left); | 2124 __ SmiTag(left); |
| 1991 break; | 2125 break; |
| 1992 } | 2126 } |
| 1993 case Token::kSHL: { | |
| 1994 // shlq operation masks the count to 6 bits. | |
| 1995 const intptr_t kCountLimit = 0x3F; | |
| 1996 intptr_t value = Smi::Cast(constant).Value(); | |
| 1997 if (value == 0) break; | |
| 1998 if ((value < 0) || (value >= kCountLimit)) { | |
| 1999 // This condition may not be known earlier in some cases because | |
| 2000 // of constant propagation, inlining, etc. | |
| 2001 __ jmp(deopt); | |
| 2002 break; | |
| 2003 } | |
| 2004 Register temp = locs()->temp(0).reg(); | |
| 2005 __ movq(temp, left); | |
| 2006 __ shlq(left, Immediate(value)); | |
| 2007 __ sarq(left, Immediate(value)); | |
| 2008 __ cmpq(left, temp); | |
| 2009 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 2010 // Shift for result now we know there is no overflow. | |
| 2011 __ shlq(left, Immediate(value)); | |
| 2012 break; | |
| 2013 } | |
| 2014 | 2127 |
| 2015 default: | 2128 default: |
| 2016 UNREACHABLE(); | 2129 UNREACHABLE(); |
| 2017 break; | 2130 break; |
| 2018 } | 2131 } |
| 2019 return; | 2132 return; |
| 2020 } | 2133 } |
| 2021 | 2134 |
| 2022 Register right = locs()->in(1).reg(); | 2135 Register right = locs()->in(1).reg(); |
| 2023 switch (op_kind()) { | 2136 switch (op_kind()) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2087 __ j(LESS, &count_ok, Assembler::kNearJump); | 2200 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 2088 __ movq(right, Immediate(kCountLimit)); | 2201 __ movq(right, Immediate(kCountLimit)); |
| 2089 __ Bind(&count_ok); | 2202 __ Bind(&count_ok); |
| 2090 } | 2203 } |
| 2091 ASSERT(right == RCX); // Count must be in RCX | 2204 ASSERT(right == RCX); // Count must be in RCX |
| 2092 __ SmiUntag(left); | 2205 __ SmiUntag(left); |
| 2093 __ sarq(left, right); | 2206 __ sarq(left, right); |
| 2094 __ SmiTag(left); | 2207 __ SmiTag(left); |
| 2095 break; | 2208 break; |
| 2096 } | 2209 } |
| 2097 case Token::kSHL: { | |
| 2098 Range* right_range = this->right()->definition()->range(); | |
| 2099 if (this->left()->BindsToConstant()) { | |
| 2100 // If left is constant, we know the maximal allowed size for right. | |
| 2101 const Object& obj = this->left()->BoundConstant(); | |
| 2102 if (obj.IsSmi()) { | |
| 2103 const intptr_t left_int = Smi::Cast(obj).Value(); | |
| 2104 if (left_int == 0) { | |
| 2105 __ cmpq(right, Immediate(0)); | |
| 2106 __ j(NEGATIVE, deopt); | |
| 2107 break; | |
| 2108 } | |
| 2109 intptr_t tmp = (left_int > 0) ? left_int : ~left_int; | |
| 2110 intptr_t max_right = kSmiBits; | |
| 2111 while ((tmp >>= 1) != 0) { | |
| 2112 max_right--; | |
| 2113 } | |
| 2114 const bool right_needs_check = | |
| 2115 (right_range == NULL) || | |
| 2116 !right_range->IsWithin(0, max_right - 1); | |
| 2117 if (right_needs_check) { | |
| 2118 __ cmpq(right, | |
| 2119 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right)))); | |
| 2120 __ j(ABOVE_EQUAL, deopt); | |
| 2121 } | |
| 2122 __ SmiUntag(right); | |
| 2123 __ shlq(left, right); | |
| 2124 break; | |
| 2125 } | |
| 2126 } | |
| 2127 Register temp = locs()->temp(0).reg(); | |
| 2128 // Check if count too large for handling it inlined. | |
| 2129 __ movq(temp, left); | |
| 2130 const bool right_needs_check = | |
| 2131 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); | |
| 2132 if (right_needs_check) { | |
| 2133 __ cmpq(right, | |
| 2134 Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits)))); | |
| 2135 __ j(ABOVE_EQUAL, deopt); | |
| 2136 } | |
| 2137 ASSERT(right == RCX); // Count must be in RCX | |
| 2138 __ SmiUntag(right); | |
| 2139 // Overflow test (preserve temp and right); | |
| 2140 __ shlq(left, right); | |
| 2141 __ sarq(left, right); | |
| 2142 __ cmpq(left, temp); | |
| 2143 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 2144 // Shift for result now we know there is no overflow. | |
| 2145 __ shlq(left, right); | |
| 2146 break; | |
| 2147 } | |
| 2148 case Token::kDIV: { | 2210 case Token::kDIV: { |
| 2149 // Dispatches to 'Double./'. | 2211 // Dispatches to 'Double./'. |
| 2150 // TODO(srdjan): Implement as conversion to double and double division. | 2212 // TODO(srdjan): Implement as conversion to double and double division. |
| 2151 UNREACHABLE(); | 2213 UNREACHABLE(); |
| 2152 break; | 2214 break; |
| 2153 } | 2215 } |
| 2154 case Token::kMOD: { | 2216 case Token::kMOD: { |
| 2155 // TODO(srdjan): Implement. | 2217 // TODO(srdjan): Implement. |
| 2156 UNREACHABLE(); | 2218 UNREACHABLE(); |
| 2157 break; | 2219 break; |
| (...skipping 950 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3108 PcDescriptors::kOther, | 3170 PcDescriptors::kOther, |
| 3109 locs()); | 3171 locs()); |
| 3110 __ Drop(2); // Discard type arguments and receiver. | 3172 __ Drop(2); // Discard type arguments and receiver. |
| 3111 } | 3173 } |
| 3112 | 3174 |
| 3113 } // namespace dart | 3175 } // namespace dart |
| 3114 | 3176 |
| 3115 #undef __ | 3177 #undef __ |
| 3116 | 3178 |
| 3117 #endif // defined TARGET_ARCH_X64 | 3179 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |