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

Side by Side Diff: runtime/vm/intermediate_language_x64.cc

Issue 12218181: Recognize pattern (a << b) & c with c being a positive Smi and allow left shift to truncate the res… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 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
OLDNEW
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
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 // Check for overflow.
1849 Register temp = locs.temp(0).reg();
1850 __ movq(temp, left);
1851 __ shlq(left, Immediate(value));
1852 __ sarq(left, Immediate(value));
1853 __ cmpq(left, temp);
1854 __ j(NOT_EQUAL, deopt); // Overflow.
1855 }
1856 // Shift for result now we know there is no overflow.
1857 __ shlq(left, Immediate(value));
1858 }
1859 return;
1860 }
1861
1862 // Right (locs.in(1)) is not constant.
1863 Register right = locs.in(1).reg();
1864 Range* right_range = shift_left->right()->definition()->range();
1865 if (shift_left->left()->BindsToConstant() && !is_truncating) {
1866 // TODO(srdjan): Implement code below for is_truncating().
1867 // If left is constant, we know the maximal allowed size for right.
1868 const Object& obj = shift_left->left()->BoundConstant();
1869 if (obj.IsSmi()) {
1870 const intptr_t left_int = Smi::Cast(obj).Value();
1871 if (left_int == 0) {
1872 __ cmpq(right, Immediate(0));
1873 __ j(NEGATIVE, deopt);
1874 return;
1875 }
1876 intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
1877 intptr_t max_right = kSmiBits;
1878 while ((tmp >>= 1) != 0) {
1879 max_right--;
1880 }
1881 const bool right_needs_check =
1882 (right_range == NULL) ||
1883 !right_range->IsWithin(0, max_right - 1);
1884 if (right_needs_check) {
1885 __ cmpq(right,
1886 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
1887 __ j(ABOVE_EQUAL, deopt);
1888 }
1889 __ SmiUntag(right);
1890 __ shlq(left, right);
1891 }
1892 return;
1893 }
1894
1895 const bool right_needs_check =
1896 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
1897 ASSERT(right == RCX); // Count must be in RCX
1898 if (is_truncating) {
1899 if (right_needs_check) {
1900 const bool right_may_be_negative =
1901 (right_range == NULL) ||
1902 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
1903 if (right_may_be_negative) {
1904 ASSERT(shift_left->CanDeoptimize());
1905 __ cmpq(right, Immediate(0));
1906 __ j(NEGATIVE, deopt);
1907 }
1908 Label done, is_not_zero;
1909 __ cmpq(right,
1910 Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
1911 __ j(BELOW, &is_not_zero, Assembler::kNearJump);
1912 __ xorq(left, left);
1913 __ jmp(&done, Assembler::kNearJump);
1914 __ Bind(&is_not_zero);
1915 __ SmiUntag(right);
1916 __ shlq(left, right);
1917 __ Bind(&done);
1918 } else {
1919 __ SmiUntag(right);
1920 __ shlq(left, right);
1921 }
1922 } else {
1923 if (right_needs_check) {
1924 ASSERT(shift_left->CanDeoptimize());
1925 __ cmpq(right,
1926 Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
1927 __ j(ABOVE_EQUAL, deopt);
1928 }
1929 // Left is not a constant.
1930 Register temp = locs.temp(0).reg();
1931 // Check if count too large for handling it inlined.
1932 __ movq(temp, left);
1933 __ SmiUntag(right);
1934 // Overflow test (preserve temp and right);
1935 __ shlq(left, right);
1936 __ sarq(left, right);
1937 __ cmpq(left, temp);
1938 __ j(NOT_EQUAL, deopt); // Overflow.
1939 // Shift for result now we know there is no overflow.
1940 __ shlq(left, right);
1941 }
1942 }
1943
1944
1820 static bool CanBeImmediate(const Object& constant) { 1945 static bool CanBeImmediate(const Object& constant) {
1821 return constant.IsSmi() && 1946 return constant.IsSmi() &&
1822 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32(); 1947 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32();
1823 } 1948 }
1824 1949
1825 1950
1826 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { 1951 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
1827 const intptr_t kNumInputs = 2; 1952 const intptr_t kNumInputs = 2;
1828 1953
1829 ConstantInstr* right_constant = right()->definition()->AsConstant(); 1954 ConstantInstr* right_constant = right()->definition()->AsConstant();
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1862 return summary; 1987 return summary;
1863 } else if (op_kind() == Token::kSHR) { 1988 } else if (op_kind() == Token::kSHR) {
1864 const intptr_t kNumTemps = 0; 1989 const intptr_t kNumTemps = 0;
1865 LocationSummary* summary = 1990 LocationSummary* summary =
1866 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 1991 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
1867 summary->set_in(0, Location::RequiresRegister()); 1992 summary->set_in(0, Location::RequiresRegister());
1868 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); 1993 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX));
1869 summary->set_out(Location::SameAsFirstInput()); 1994 summary->set_out(Location::SameAsFirstInput());
1870 return summary; 1995 return summary;
1871 } else if (op_kind() == Token::kSHL) { 1996 } else if (op_kind() == Token::kSHL) {
1872 const intptr_t kNumTemps = 1; 1997 const intptr_t kNumTemps = 0;
1873 LocationSummary* summary = 1998 LocationSummary* summary =
1874 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 1999 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
1875 summary->set_in(0, Location::RequiresRegister()); 2000 summary->set_in(0, Location::RequiresRegister());
1876 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); 2001 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX));
1877 summary->set_temp(0, Location::RequiresRegister()); 2002 if (!is_truncating()) {
2003 summary->AddTemp(Location::RequiresRegister());
2004 }
1878 summary->set_out(Location::SameAsFirstInput()); 2005 summary->set_out(Location::SameAsFirstInput());
1879 return summary; 2006 return summary;
1880 } else { 2007 } else {
1881 const intptr_t kNumTemps = 0; 2008 const intptr_t kNumTemps = 0;
1882 LocationSummary* summary = 2009 LocationSummary* summary =
1883 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 2010 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
1884 summary->set_in(0, Location::RequiresRegister()); 2011 summary->set_in(0, Location::RequiresRegister());
1885 summary->set_in(1, Location::RegisterOrSmiConstant(right())); 2012 summary->set_in(1, Location::RegisterOrSmiConstant(right()));
1886 summary->set_out(Location::SameAsFirstInput()); 2013 summary->set_out(Location::SameAsFirstInput());
1887 return summary; 2014 return summary;
1888 } 2015 }
1889 } 2016 }
1890 2017
1891 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 2018 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2019 if (op_kind() == Token::kSHL) {
2020 EmitSmiShiftLeft(compiler, this);
2021 return;
2022 }
2023
2024 ASSERT(!is_truncating());
1892 Register left = locs()->in(0).reg(); 2025 Register left = locs()->in(0).reg();
1893 Register result = locs()->out().reg(); 2026 Register result = locs()->out().reg();
1894 ASSERT(left == result); 2027 ASSERT(left == result);
1895 Label* deopt = NULL; 2028 Label* deopt = NULL;
1896 if (CanDeoptimize()) { 2029 if (CanDeoptimize()) {
1897 deopt = compiler->AddDeoptStub(deopt_id(), 2030 deopt = compiler->AddDeoptStub(deopt_id(),
1898 kDeoptBinarySmiOp); 2031 kDeoptBinarySmiOp);
1899 } 2032 }
1900 2033
1901 if (locs()->in(1).IsConstant()) { 2034 if (locs()->in(1).IsConstant()) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1983 break; 2116 break;
1984 } 2117 }
1985 2118
1986 value = value + kSmiTagSize; 2119 value = value + kSmiTagSize;
1987 if (value >= kCountLimit) value = kCountLimit; 2120 if (value >= kCountLimit) value = kCountLimit;
1988 2121
1989 __ sarq(left, Immediate(value)); 2122 __ sarq(left, Immediate(value));
1990 __ SmiTag(left); 2123 __ SmiTag(left);
1991 break; 2124 break;
1992 } 2125 }
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 2126
2015 default: 2127 default:
2016 UNREACHABLE(); 2128 UNREACHABLE();
2017 break; 2129 break;
2018 } 2130 }
2019 return; 2131 return;
2020 } 2132 }
2021 2133
2022 Register right = locs()->in(1).reg(); 2134 Register right = locs()->in(1).reg();
2023 switch (op_kind()) { 2135 switch (op_kind()) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
2087 __ j(LESS, &count_ok, Assembler::kNearJump); 2199 __ j(LESS, &count_ok, Assembler::kNearJump);
2088 __ movq(right, Immediate(kCountLimit)); 2200 __ movq(right, Immediate(kCountLimit));
2089 __ Bind(&count_ok); 2201 __ Bind(&count_ok);
2090 } 2202 }
2091 ASSERT(right == RCX); // Count must be in RCX 2203 ASSERT(right == RCX); // Count must be in RCX
2092 __ SmiUntag(left); 2204 __ SmiUntag(left);
2093 __ sarq(left, right); 2205 __ sarq(left, right);
2094 __ SmiTag(left); 2206 __ SmiTag(left);
2095 break; 2207 break;
2096 } 2208 }
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: { 2209 case Token::kDIV: {
2149 // Dispatches to 'Double./'. 2210 // Dispatches to 'Double./'.
2150 // TODO(srdjan): Implement as conversion to double and double division. 2211 // TODO(srdjan): Implement as conversion to double and double division.
2151 UNREACHABLE(); 2212 UNREACHABLE();
2152 break; 2213 break;
2153 } 2214 }
2154 case Token::kMOD: { 2215 case Token::kMOD: {
2155 // TODO(srdjan): Implement. 2216 // TODO(srdjan): Implement.
2156 UNREACHABLE(); 2217 UNREACHABLE();
2157 break; 2218 break;
(...skipping 950 matching lines...) Expand 10 before | Expand all | Expand 10 after
3108 PcDescriptors::kOther, 3169 PcDescriptors::kOther,
3109 locs()); 3170 locs());
3110 __ Drop(2); // Discard type arguments and receiver. 3171 __ Drop(2); // Discard type arguments and receiver.
3111 } 3172 }
3112 3173
3113 } // namespace dart 3174 } // namespace dart
3114 3175
3115 #undef __ 3176 #undef __
3116 3177
3117 #endif // defined TARGET_ARCH_X64 3178 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language_ia32.cc ('k') | tests/standalone/left_shift_bit_and_op_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698