| 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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 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 1981 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1992 CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this); | 1992 CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this); |
| 1993 compiler->AddSlowPathCode(slow_path); | 1993 compiler->AddSlowPathCode(slow_path); |
| 1994 | 1994 |
| 1995 __ cmpl(ESP, | 1995 __ cmpl(ESP, |
| 1996 Address::Absolute(Isolate::Current()->stack_limit_address())); | 1996 Address::Absolute(Isolate::Current()->stack_limit_address())); |
| 1997 __ j(BELOW_EQUAL, slow_path->entry_label()); | 1997 __ j(BELOW_EQUAL, slow_path->entry_label()); |
| 1998 __ Bind(slow_path->exit_label()); | 1998 __ Bind(slow_path->exit_label()); |
| 1999 } | 1999 } |
| 2000 | 2000 |
| 2001 | 2001 |
| 2002 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 2003 BinarySmiOpInstr* shift_left) { |
| 2004 const bool is_truncating = shift_left->is_truncating(); |
| 2005 const LocationSummary& locs = *shift_left->locs(); |
| 2006 Register left = locs.in(0).reg(); |
| 2007 Register result = locs.out().reg(); |
| 2008 ASSERT(left == result); |
| 2009 Label* deopt = shift_left->CanDeoptimize() ? |
| 2010 compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL; |
| 2011 if (locs.in(1).IsConstant()) { |
| 2012 const Object& constant = locs.in(1).constant(); |
| 2013 ASSERT(constant.IsSmi()); |
| 2014 // shll operation masks the count to 5 bits. |
| 2015 const intptr_t kCountLimit = 0x1F; |
| 2016 const intptr_t value = Smi::Cast(constant).Value(); |
| 2017 if (value == 0) { |
| 2018 // No code needed. |
| 2019 } else if ((value < 0) || (value >= kCountLimit)) { |
| 2020 // This condition may not be known earlier in some cases because |
| 2021 // of constant propagation, inlining, etc. |
| 2022 if ((value >=kCountLimit) && is_truncating) { |
| 2023 __ xorl(result, result); |
| 2024 } else { |
| 2025 // Result is Mint or exception. |
| 2026 __ jmp(deopt); |
| 2027 } |
| 2028 } else { |
| 2029 if (!is_truncating) { |
| 2030 // Check for overflow. |
| 2031 Register temp = locs.temp(0).reg(); |
| 2032 __ movl(temp, left); |
| 2033 __ shll(left, Immediate(value)); |
| 2034 __ sarl(left, Immediate(value)); |
| 2035 __ cmpl(left, temp); |
| 2036 __ j(NOT_EQUAL, deopt); // Overflow. |
| 2037 } |
| 2038 // Shift for result now we know there is no overflow. |
| 2039 __ shll(left, Immediate(value)); |
| 2040 } |
| 2041 return; |
| 2042 } |
| 2043 |
| 2044 // Right (locs.in(1)) is not constant. |
| 2045 Register right = locs.in(1).reg(); |
| 2046 Range* right_range = shift_left->right()->definition()->range(); |
| 2047 if (shift_left->left()->BindsToConstant() && !is_truncating) { |
| 2048 // TODO(srdjan): Implement code below for is_truncating(). |
| 2049 // If left is constant, we know the maximal allowed size for right. |
| 2050 const Object& obj = shift_left->left()->BoundConstant(); |
| 2051 if (obj.IsSmi()) { |
| 2052 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 2053 if (left_int == 0) { |
| 2054 __ cmpl(right, Immediate(0)); |
| 2055 __ j(NEGATIVE, deopt); |
| 2056 return; |
| 2057 } |
| 2058 intptr_t tmp = (left_int > 0) ? left_int : ~left_int; |
| 2059 intptr_t max_right = kSmiBits; |
| 2060 while ((tmp >>= 1) != 0) { |
| 2061 max_right--; |
| 2062 } |
| 2063 const bool right_needs_check = |
| 2064 (right_range == NULL) || |
| 2065 !right_range->IsWithin(0, max_right - 1); |
| 2066 if (right_needs_check) { |
| 2067 __ cmpl(right, |
| 2068 Immediate(reinterpret_cast<int32_t>(Smi::New(max_right)))); |
| 2069 __ j(ABOVE_EQUAL, deopt); |
| 2070 } |
| 2071 __ SmiUntag(right); |
| 2072 __ shll(left, right); |
| 2073 } |
| 2074 return; |
| 2075 } |
| 2076 |
| 2077 const bool right_needs_check = |
| 2078 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); |
| 2079 ASSERT(right == ECX); // Count must be in ECX |
| 2080 if (is_truncating) { |
| 2081 if (right_needs_check) { |
| 2082 const bool right_may_be_negative = |
| 2083 (right_range == NULL) || |
| 2084 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); |
| 2085 if (right_may_be_negative) { |
| 2086 ASSERT(shift_left->CanDeoptimize()); |
| 2087 __ cmpl(right, Immediate(0)); |
| 2088 __ j(NEGATIVE, deopt); |
| 2089 } |
| 2090 Label done, is_not_zero; |
| 2091 __ cmpl(right, |
| 2092 Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); |
| 2093 __ j(BELOW, &is_not_zero, Assembler::kNearJump); |
| 2094 __ xorl(left, left); |
| 2095 __ jmp(&done, Assembler::kNearJump); |
| 2096 __ Bind(&is_not_zero); |
| 2097 __ SmiUntag(right); |
| 2098 __ shll(left, right); |
| 2099 __ Bind(&done); |
| 2100 } else { |
| 2101 __ SmiUntag(right); |
| 2102 __ shll(left, right); |
| 2103 } |
| 2104 } else { |
| 2105 if (right_needs_check) { |
| 2106 ASSERT(shift_left->CanDeoptimize()); |
| 2107 __ cmpl(right, |
| 2108 Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); |
| 2109 __ j(ABOVE_EQUAL, deopt); |
| 2110 } |
| 2111 // Left is not a constant. |
| 2112 Register temp = locs.temp(0).reg(); |
| 2113 // Check if count too large for handling it inlined. |
| 2114 __ movl(temp, left); |
| 2115 __ SmiUntag(right); |
| 2116 // Overflow test (preserve temp and right); |
| 2117 __ shll(left, right); |
| 2118 __ sarl(left, right); |
| 2119 __ cmpl(left, temp); |
| 2120 __ j(NOT_EQUAL, deopt); // Overflow. |
| 2121 // Shift for result now we know there is no overflow. |
| 2122 __ shll(left, right); |
| 2123 } |
| 2124 } |
| 2125 |
| 2126 |
| 2002 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 2127 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| 2003 const intptr_t kNumInputs = 2; | 2128 const intptr_t kNumInputs = 2; |
| 2004 if (op_kind() == Token::kTRUNCDIV) { | 2129 if (op_kind() == Token::kTRUNCDIV) { |
| 2005 const intptr_t kNumTemps = 1; | 2130 const intptr_t kNumTemps = 1; |
| 2006 LocationSummary* summary = | 2131 LocationSummary* summary = |
| 2007 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2132 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2008 if (RightIsPowerOfTwoConstant()) { | 2133 if (RightIsPowerOfTwoConstant()) { |
| 2009 summary->set_in(0, Location::RequiresRegister()); | 2134 summary->set_in(0, Location::RequiresRegister()); |
| 2010 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2135 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2011 summary->set_in(1, Location::Constant(right_constant->value())); | 2136 summary->set_in(1, Location::Constant(right_constant->value())); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2022 return summary; | 2147 return summary; |
| 2023 } else if (op_kind() == Token::kSHR) { | 2148 } else if (op_kind() == Token::kSHR) { |
| 2024 const intptr_t kNumTemps = 0; | 2149 const intptr_t kNumTemps = 0; |
| 2025 LocationSummary* summary = | 2150 LocationSummary* summary = |
| 2026 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2151 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2027 summary->set_in(0, Location::RequiresRegister()); | 2152 summary->set_in(0, Location::RequiresRegister()); |
| 2028 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); | 2153 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| 2029 summary->set_out(Location::SameAsFirstInput()); | 2154 summary->set_out(Location::SameAsFirstInput()); |
| 2030 return summary; | 2155 return summary; |
| 2031 } else if (op_kind() == Token::kSHL) { | 2156 } else if (op_kind() == Token::kSHL) { |
| 2032 const intptr_t kNumTemps = 1; | 2157 const intptr_t kNumTemps = 0; |
| 2033 LocationSummary* summary = | 2158 LocationSummary* summary = |
| 2034 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2159 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2035 summary->set_in(0, Location::RequiresRegister()); | 2160 summary->set_in(0, Location::RequiresRegister()); |
| 2036 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); | 2161 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| 2037 summary->set_temp(0, Location::RequiresRegister()); | 2162 if (!is_truncating()) { |
| 2163 summary->AddTemp(Location::RequiresRegister()); |
| 2164 } |
| 2038 summary->set_out(Location::SameAsFirstInput()); | 2165 summary->set_out(Location::SameAsFirstInput()); |
| 2039 return summary; | 2166 return summary; |
| 2040 } else { | 2167 } else { |
| 2041 const intptr_t kNumTemps = 0; | 2168 const intptr_t kNumTemps = 0; |
| 2042 LocationSummary* summary = | 2169 LocationSummary* summary = |
| 2043 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2170 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2044 summary->set_in(0, Location::RequiresRegister()); | 2171 summary->set_in(0, Location::RequiresRegister()); |
| 2045 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 2172 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 2046 summary->set_out(Location::SameAsFirstInput()); | 2173 summary->set_out(Location::SameAsFirstInput()); |
| 2047 return summary; | 2174 return summary; |
| 2048 } | 2175 } |
| 2049 } | 2176 } |
| 2050 | 2177 |
| 2051 | 2178 |
| 2052 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2179 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2180 if (op_kind() == Token::kSHL) { |
| 2181 EmitSmiShiftLeft(compiler, this); |
| 2182 return; |
| 2183 } |
| 2184 |
| 2185 ASSERT(!is_truncating()); |
| 2053 Register left = locs()->in(0).reg(); | 2186 Register left = locs()->in(0).reg(); |
| 2054 Register result = locs()->out().reg(); | 2187 Register result = locs()->out().reg(); |
| 2055 ASSERT(left == result); | 2188 ASSERT(left == result); |
| 2056 Label* deopt = NULL; | 2189 Label* deopt = NULL; |
| 2057 if (CanDeoptimize()) { | 2190 if (CanDeoptimize()) { |
| 2058 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); | 2191 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); |
| 2059 } | 2192 } |
| 2060 | 2193 |
| 2061 if (locs()->in(1).IsConstant()) { | 2194 if (locs()->in(1).IsConstant()) { |
| 2062 const Object& constant = locs()->in(1).constant(); | 2195 const Object& constant = locs()->in(1).constant(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2140 break; | 2273 break; |
| 2141 } | 2274 } |
| 2142 | 2275 |
| 2143 value = value + kSmiTagSize; | 2276 value = value + kSmiTagSize; |
| 2144 if (value >= kCountLimit) value = kCountLimit; | 2277 if (value >= kCountLimit) value = kCountLimit; |
| 2145 | 2278 |
| 2146 __ sarl(left, Immediate(value)); | 2279 __ sarl(left, Immediate(value)); |
| 2147 __ SmiTag(left); | 2280 __ SmiTag(left); |
| 2148 break; | 2281 break; |
| 2149 } | 2282 } |
| 2150 case Token::kSHL: { | |
| 2151 // shll operation masks the count to 5 bits. | |
| 2152 const intptr_t kCountLimit = 0x1F; | |
| 2153 intptr_t value = Smi::Cast(constant).Value(); | |
| 2154 if (value == 0) break; | |
| 2155 if ((value < 0) || (value >= kCountLimit)) { | |
| 2156 // This condition may not be known earlier in some cases because | |
| 2157 // of constant propagation, inlining, etc. | |
| 2158 __ jmp(deopt); | |
| 2159 break; | |
| 2160 } | |
| 2161 Register temp = locs()->temp(0).reg(); | |
| 2162 __ movl(temp, left); | |
| 2163 __ shll(left, Immediate(value)); | |
| 2164 __ sarl(left, Immediate(value)); | |
| 2165 __ cmpl(left, temp); | |
| 2166 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 2167 // Shift for result now we know there is no overflow. | |
| 2168 __ shll(left, Immediate(value)); | |
| 2169 break; | |
| 2170 } | |
| 2171 | 2283 |
| 2172 default: | 2284 default: |
| 2173 UNREACHABLE(); | 2285 UNREACHABLE(); |
| 2174 break; | 2286 break; |
| 2175 } | 2287 } |
| 2176 return; | 2288 return; |
| 2177 } | 2289 } |
| 2178 | 2290 |
| 2179 Register right = locs()->in(1).reg(); | 2291 Register right = locs()->in(1).reg(); |
| 2180 switch (op_kind()) { | 2292 switch (op_kind()) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2244 __ j(LESS, &count_ok, Assembler::kNearJump); | 2356 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 2245 __ movl(right, Immediate(kCountLimit)); | 2357 __ movl(right, Immediate(kCountLimit)); |
| 2246 __ Bind(&count_ok); | 2358 __ Bind(&count_ok); |
| 2247 } | 2359 } |
| 2248 ASSERT(right == ECX); // Count must be in ECX | 2360 ASSERT(right == ECX); // Count must be in ECX |
| 2249 __ SmiUntag(left); | 2361 __ SmiUntag(left); |
| 2250 __ sarl(left, right); | 2362 __ sarl(left, right); |
| 2251 __ SmiTag(left); | 2363 __ SmiTag(left); |
| 2252 break; | 2364 break; |
| 2253 } | 2365 } |
| 2254 case Token::kSHL: { | |
| 2255 Range* right_range = this->right()->definition()->range(); | |
| 2256 if (this->left()->BindsToConstant()) { | |
| 2257 // If left is constant, we know the maximal allowed size for right. | |
| 2258 const Object& obj = this->left()->BoundConstant(); | |
| 2259 if (obj.IsSmi()) { | |
| 2260 const intptr_t left_int = Smi::Cast(obj).Value(); | |
| 2261 if (left_int == 0) { | |
| 2262 __ cmpl(right, Immediate(0)); | |
| 2263 __ j(NEGATIVE, deopt); | |
| 2264 break; | |
| 2265 } | |
| 2266 intptr_t tmp = (left_int > 0) ? left_int : ~left_int; | |
| 2267 intptr_t max_right = kSmiBits; | |
| 2268 while ((tmp >>= 1) != 0) { | |
| 2269 max_right--; | |
| 2270 } | |
| 2271 const bool right_needs_check = | |
| 2272 (right_range == NULL) || | |
| 2273 !right_range->IsWithin(0, max_right - 1); | |
| 2274 if (right_needs_check) { | |
| 2275 __ cmpl(right, | |
| 2276 Immediate(reinterpret_cast<int32_t>(Smi::New(max_right)))); | |
| 2277 __ j(ABOVE_EQUAL, deopt); | |
| 2278 } | |
| 2279 __ SmiUntag(right); | |
| 2280 __ shll(left, right); | |
| 2281 break; | |
| 2282 } | |
| 2283 } | |
| 2284 Register temp = locs()->temp(0).reg(); | |
| 2285 // Check if count too large for handling it inlined. | |
| 2286 __ movl(temp, left); | |
| 2287 const bool right_needs_check = | |
| 2288 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); | |
| 2289 if (right_needs_check) { | |
| 2290 __ cmpl(right, | |
| 2291 Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); | |
| 2292 __ j(ABOVE_EQUAL, deopt); | |
| 2293 } | |
| 2294 ASSERT(right == ECX); // Count must be in ECX | |
| 2295 __ SmiUntag(right); | |
| 2296 // Overflow test (preserve temp and right); | |
| 2297 __ shll(left, right); | |
| 2298 __ sarl(left, right); | |
| 2299 __ cmpl(left, temp); | |
| 2300 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 2301 // Shift for result now we know there is no overflow. | |
| 2302 __ shll(left, right); | |
| 2303 break; | |
| 2304 } | |
| 2305 case Token::kDIV: { | 2366 case Token::kDIV: { |
| 2306 // Dispatches to 'Double./'. | 2367 // Dispatches to 'Double./'. |
| 2307 // TODO(srdjan): Implement as conversion to double and double division. | 2368 // TODO(srdjan): Implement as conversion to double and double division. |
| 2308 UNREACHABLE(); | 2369 UNREACHABLE(); |
| 2309 break; | 2370 break; |
| 2310 } | 2371 } |
| 2311 case Token::kMOD: { | 2372 case Token::kMOD: { |
| 2312 // TODO(srdjan): Implement. | 2373 // TODO(srdjan): Implement. |
| 2313 UNREACHABLE(); | 2374 UNREACHABLE(); |
| 2314 break; | 2375 break; |
| (...skipping 1190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3505 PcDescriptors::kOther, | 3566 PcDescriptors::kOther, |
| 3506 locs()); | 3567 locs()); |
| 3507 __ Drop(2); // Discard type arguments and receiver. | 3568 __ Drop(2); // Discard type arguments and receiver. |
| 3508 } | 3569 } |
| 3509 | 3570 |
| 3510 } // namespace dart | 3571 } // namespace dart |
| 3511 | 3572 |
| 3512 #undef __ | 3573 #undef __ |
| 3513 | 3574 |
| 3514 #endif // defined TARGET_ARCH_IA32 | 3575 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |