Chromium Code Reviews| 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 __ shll(left, Immediate(value)); | |
| 2031 } else { | |
| 2032 Register temp = locs.temp(0).reg(); | |
| 2033 __ movl(temp, left); | |
| 2034 __ shll(left, Immediate(value)); | |
| 2035 __ sarl(left, Immediate(value)); | |
| 2036 __ cmpl(left, temp); | |
| 2037 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 2038 // Shift for result now we know there is no overflow. | |
| 2039 __ shll(left, Immediate(value)); | |
| 2040 } | |
|
Vyacheslav Egorov (Google)
2013/02/20 00:37:06
Consider:
2029 if (!is_truncating) {
2032
srdjan
2013/02/21 00:47:17
Done.
| |
| 2041 } | |
| 2042 return; | |
| 2043 } | |
| 2044 | |
| 2045 // Right (locs.in(1)) is not constant. | |
| 2046 Register right = locs.in(1).reg(); | |
| 2047 Range* right_range = shift_left->right()->definition()->range(); | |
| 2048 if (shift_left->left()->BindsToConstant() && !is_truncating) { | |
| 2049 // TODO(srdjan): Implement code below for is_truncating(). | |
| 2050 // If left is constant, we know the maximal allowed size for right. | |
| 2051 const Object& obj = shift_left->left()->BoundConstant(); | |
| 2052 if (obj.IsSmi()) { | |
| 2053 const intptr_t left_int = Smi::Cast(obj).Value(); | |
| 2054 if (left_int == 0) { | |
| 2055 __ cmpl(right, Immediate(0)); | |
| 2056 __ j(NEGATIVE, deopt); | |
| 2057 return; | |
| 2058 } | |
| 2059 intptr_t tmp = (left_int > 0) ? left_int : ~left_int; | |
| 2060 intptr_t max_right = kSmiBits; | |
| 2061 while ((tmp >>= 1) != 0) { | |
| 2062 max_right--; | |
| 2063 } | |
| 2064 const bool right_needs_check = | |
| 2065 (right_range == NULL) || | |
| 2066 !right_range->IsWithin(0, max_right - 1); | |
| 2067 if (right_needs_check) { | |
| 2068 __ cmpl(right, | |
| 2069 Immediate(reinterpret_cast<int32_t>(Smi::New(max_right)))); | |
| 2070 __ j(ABOVE_EQUAL, deopt); | |
| 2071 } | |
| 2072 __ SmiUntag(right); | |
| 2073 __ shll(left, right); | |
| 2074 } | |
| 2075 return; | |
| 2076 } | |
| 2077 | |
| 2078 const bool right_needs_check = | |
| 2079 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); | |
| 2080 ASSERT(right == ECX); // Count must be in ECX | |
| 2081 if (is_truncating) { | |
| 2082 if (right_needs_check) { | |
| 2083 const bool right_may_be_negative = | |
| 2084 (right_range == NULL) || | |
| 2085 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); | |
| 2086 if (right_may_be_negative) { | |
| 2087 ASSERT(shift_left->CanDeoptimize()); | |
| 2088 __ cmpl(right, Immediate(0)); | |
| 2089 __ j(NEGATIVE, deopt); | |
| 2090 } | |
| 2091 Label done, is_not_zero; | |
| 2092 __ cmpl(right, | |
| 2093 Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); | |
| 2094 __ j(BELOW, &is_not_zero, Assembler::kNearJump); | |
| 2095 __ xorl(left, left); | |
| 2096 __ jmp(&done, Assembler::kNearJump); | |
| 2097 __ Bind(&is_not_zero); | |
| 2098 __ SmiUntag(right); | |
| 2099 __ shll(left, right); | |
| 2100 __ Bind(&done); | |
| 2101 } else { | |
| 2102 __ SmiUntag(right); | |
| 2103 __ shll(left, right); | |
| 2104 } | |
| 2105 } else { | |
| 2106 if (right_needs_check) { | |
| 2107 ASSERT(shift_left->CanDeoptimize()); | |
| 2108 __ cmpl(right, | |
| 2109 Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); | |
| 2110 __ j(ABOVE_EQUAL, deopt); | |
| 2111 } | |
| 2112 // Left is not a constant. | |
| 2113 Register temp = locs.temp(0).reg(); | |
| 2114 // Check if count too large for handling it inlined. | |
| 2115 __ movl(temp, left); | |
| 2116 __ SmiUntag(right); | |
| 2117 // Overflow test (preserve temp and right); | |
| 2118 __ shll(left, right); | |
| 2119 __ sarl(left, right); | |
| 2120 __ cmpl(left, temp); | |
| 2121 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 2122 // Shift for result now we know there is no overflow. | |
| 2123 __ shll(left, right); | |
| 2124 } | |
| 2125 } | |
| 2126 | |
| 2127 | |
| 2002 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 2128 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| 2003 const intptr_t kNumInputs = 2; | 2129 const intptr_t kNumInputs = 2; |
| 2004 if (op_kind() == Token::kTRUNCDIV) { | 2130 if (op_kind() == Token::kTRUNCDIV) { |
| 2005 const intptr_t kNumTemps = 1; | 2131 const intptr_t kNumTemps = 1; |
| 2006 LocationSummary* summary = | 2132 LocationSummary* summary = |
| 2007 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2133 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2008 if (RightIsPowerOfTwoConstant()) { | 2134 if (RightIsPowerOfTwoConstant()) { |
| 2009 summary->set_in(0, Location::RequiresRegister()); | 2135 summary->set_in(0, Location::RequiresRegister()); |
| 2010 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2136 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2011 summary->set_in(1, Location::Constant(right_constant->value())); | 2137 summary->set_in(1, Location::Constant(right_constant->value())); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 2022 return summary; | 2148 return summary; |
| 2023 } else if (op_kind() == Token::kSHR) { | 2149 } else if (op_kind() == Token::kSHR) { |
| 2024 const intptr_t kNumTemps = 0; | 2150 const intptr_t kNumTemps = 0; |
| 2025 LocationSummary* summary = | 2151 LocationSummary* summary = |
| 2026 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2152 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2027 summary->set_in(0, Location::RequiresRegister()); | 2153 summary->set_in(0, Location::RequiresRegister()); |
| 2028 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); | 2154 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| 2029 summary->set_out(Location::SameAsFirstInput()); | 2155 summary->set_out(Location::SameAsFirstInput()); |
| 2030 return summary; | 2156 return summary; |
| 2031 } else if (op_kind() == Token::kSHL) { | 2157 } else if (op_kind() == Token::kSHL) { |
| 2032 const intptr_t kNumTemps = 1; | 2158 const intptr_t kNumTemps = is_truncating() ? 0 : 1; |
| 2033 LocationSummary* summary = | 2159 LocationSummary* summary = |
| 2034 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2160 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2035 summary->set_in(0, Location::RequiresRegister()); | 2161 summary->set_in(0, Location::RequiresRegister()); |
| 2036 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); | 2162 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| 2037 summary->set_temp(0, Location::RequiresRegister()); | 2163 if (!is_truncating()) { |
| 2164 summary->set_temp(0, Location::RequiresRegister()); | |
|
Vyacheslav Egorov (Google)
2013/02/20 00:37:06
You can use summary->AddTemp() for simplicity. The
srdjan
2013/02/21 21:55:31
Done.
| |
| 2165 } | |
| 2038 summary->set_out(Location::SameAsFirstInput()); | 2166 summary->set_out(Location::SameAsFirstInput()); |
| 2039 return summary; | 2167 return summary; |
| 2040 } else { | 2168 } else { |
| 2041 const intptr_t kNumTemps = 0; | 2169 const intptr_t kNumTemps = 0; |
| 2042 LocationSummary* summary = | 2170 LocationSummary* summary = |
| 2043 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2171 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2044 summary->set_in(0, Location::RequiresRegister()); | 2172 summary->set_in(0, Location::RequiresRegister()); |
| 2045 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 2173 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 2046 summary->set_out(Location::SameAsFirstInput()); | 2174 summary->set_out(Location::SameAsFirstInput()); |
| 2047 return summary; | 2175 return summary; |
| 2048 } | 2176 } |
| 2049 } | 2177 } |
| 2050 | 2178 |
| 2051 | 2179 |
| 2052 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2180 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2181 if (op_kind() == Token::kSHL) { | |
| 2182 EmitSmiShiftLeft(compiler, this); | |
| 2183 return; | |
| 2184 } | |
| 2185 | |
| 2186 ASSERT(!is_truncating()); | |
| 2053 Register left = locs()->in(0).reg(); | 2187 Register left = locs()->in(0).reg(); |
| 2054 Register result = locs()->out().reg(); | 2188 Register result = locs()->out().reg(); |
| 2055 ASSERT(left == result); | 2189 ASSERT(left == result); |
| 2056 Label* deopt = NULL; | 2190 Label* deopt = NULL; |
| 2057 if (CanDeoptimize()) { | 2191 if (CanDeoptimize()) { |
| 2058 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); | 2192 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); |
| 2059 } | 2193 } |
| 2060 | 2194 |
| 2061 if (locs()->in(1).IsConstant()) { | 2195 if (locs()->in(1).IsConstant()) { |
| 2062 const Object& constant = locs()->in(1).constant(); | 2196 const Object& constant = locs()->in(1).constant(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2140 break; | 2274 break; |
| 2141 } | 2275 } |
| 2142 | 2276 |
| 2143 value = value + kSmiTagSize; | 2277 value = value + kSmiTagSize; |
| 2144 if (value >= kCountLimit) value = kCountLimit; | 2278 if (value >= kCountLimit) value = kCountLimit; |
| 2145 | 2279 |
| 2146 __ sarl(left, Immediate(value)); | 2280 __ sarl(left, Immediate(value)); |
| 2147 __ SmiTag(left); | 2281 __ SmiTag(left); |
| 2148 break; | 2282 break; |
| 2149 } | 2283 } |
| 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 | 2284 |
| 2172 default: | 2285 default: |
| 2173 UNREACHABLE(); | 2286 UNREACHABLE(); |
| 2174 break; | 2287 break; |
| 2175 } | 2288 } |
| 2176 return; | 2289 return; |
| 2177 } | 2290 } |
| 2178 | 2291 |
| 2179 Register right = locs()->in(1).reg(); | 2292 Register right = locs()->in(1).reg(); |
| 2180 switch (op_kind()) { | 2293 switch (op_kind()) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2244 __ j(LESS, &count_ok, Assembler::kNearJump); | 2357 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 2245 __ movl(right, Immediate(kCountLimit)); | 2358 __ movl(right, Immediate(kCountLimit)); |
| 2246 __ Bind(&count_ok); | 2359 __ Bind(&count_ok); |
| 2247 } | 2360 } |
| 2248 ASSERT(right == ECX); // Count must be in ECX | 2361 ASSERT(right == ECX); // Count must be in ECX |
| 2249 __ SmiUntag(left); | 2362 __ SmiUntag(left); |
| 2250 __ sarl(left, right); | 2363 __ sarl(left, right); |
| 2251 __ SmiTag(left); | 2364 __ SmiTag(left); |
| 2252 break; | 2365 break; |
| 2253 } | 2366 } |
| 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: { | 2367 case Token::kDIV: { |
| 2306 // Dispatches to 'Double./'. | 2368 // Dispatches to 'Double./'. |
| 2307 // TODO(srdjan): Implement as conversion to double and double division. | 2369 // TODO(srdjan): Implement as conversion to double and double division. |
| 2308 UNREACHABLE(); | 2370 UNREACHABLE(); |
| 2309 break; | 2371 break; |
| 2310 } | 2372 } |
| 2311 case Token::kMOD: { | 2373 case Token::kMOD: { |
| 2312 // TODO(srdjan): Implement. | 2374 // TODO(srdjan): Implement. |
| 2313 UNREACHABLE(); | 2375 UNREACHABLE(); |
| 2314 break; | 2376 break; |
| (...skipping 1190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3505 PcDescriptors::kOther, | 3567 PcDescriptors::kOther, |
| 3506 locs()); | 3568 locs()); |
| 3507 __ Drop(2); // Discard type arguments and receiver. | 3569 __ Drop(2); // Discard type arguments and receiver. |
| 3508 } | 3570 } |
| 3509 | 3571 |
| 3510 } // namespace dart | 3572 } // namespace dart |
| 3511 | 3573 |
| 3512 #undef __ | 3574 #undef __ |
| 3513 | 3575 |
| 3514 #endif // defined TARGET_ARCH_IA32 | 3576 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |