| 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 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 2136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2147 } | 2147 } |
| 2148 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); | 2148 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); |
| 2149 const bool right_needs_check = | 2149 const bool right_needs_check = |
| 2150 (right_range == NULL) || | 2150 (right_range == NULL) || |
| 2151 !right_range->IsWithin(0, max_right - 1); | 2151 !right_range->IsWithin(0, max_right - 1); |
| 2152 if (right_needs_check) { | 2152 if (right_needs_check) { |
| 2153 __ cmp(right, | 2153 __ cmp(right, |
| 2154 ShifterOperand(reinterpret_cast<int32_t>(Smi::New(max_right)))); | 2154 ShifterOperand(reinterpret_cast<int32_t>(Smi::New(max_right)))); |
| 2155 __ b(deopt, CS); | 2155 __ b(deopt, CS); |
| 2156 } | 2156 } |
| 2157 __ SmiUntag(right); | 2157 __ Asr(IP, right, kSmiTagSize); // SmiUntag right into IP. |
| 2158 __ Lsl(result, left, right); | 2158 __ Lsl(result, left, IP); |
| 2159 } | 2159 } |
| 2160 return; | 2160 return; |
| 2161 } | 2161 } |
| 2162 | 2162 |
| 2163 const bool right_needs_check = | 2163 const bool right_needs_check = |
| 2164 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); | 2164 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); |
| 2165 if (is_truncating) { | 2165 if (is_truncating) { |
| 2166 if (right_needs_check) { | 2166 if (right_needs_check) { |
| 2167 const bool right_may_be_negative = | 2167 const bool right_may_be_negative = |
| 2168 (right_range == NULL) || | 2168 (right_range == NULL) || |
| 2169 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); | 2169 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); |
| 2170 if (right_may_be_negative) { | 2170 if (right_may_be_negative) { |
| 2171 ASSERT(shift_left->CanDeoptimize()); | 2171 ASSERT(shift_left->CanDeoptimize()); |
| 2172 __ cmp(right, ShifterOperand(0)); | 2172 __ cmp(right, ShifterOperand(0)); |
| 2173 __ b(deopt, MI); | 2173 __ b(deopt, MI); |
| 2174 } | 2174 } |
| 2175 | 2175 |
| 2176 __ cmp(right, | 2176 __ cmp(right, |
| 2177 ShifterOperand(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); | 2177 ShifterOperand(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); |
| 2178 __ mov(result, ShifterOperand(0), CS); | 2178 __ mov(result, ShifterOperand(0), CS); |
| 2179 __ SmiUntag(right, CC); | 2179 __ Asr(IP, right, kSmiTagSize, CC); // SmiUntag right into IP if CC. |
| 2180 __ Lsl(result, left, right, CC); | 2180 __ Lsl(result, left, IP, CC); |
| 2181 } else { | 2181 } else { |
| 2182 __ SmiUntag(right); | 2182 __ Asr(IP, right, kSmiTagSize); // SmiUntag right into IP. |
| 2183 __ Lsl(result, left, right); | 2183 __ Lsl(result, left, IP); |
| 2184 } | 2184 } |
| 2185 } else { | 2185 } else { |
| 2186 if (right_needs_check) { | 2186 if (right_needs_check) { |
| 2187 ASSERT(shift_left->CanDeoptimize()); | 2187 ASSERT(shift_left->CanDeoptimize()); |
| 2188 __ cmp(right, | 2188 __ cmp(right, |
| 2189 ShifterOperand(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); | 2189 ShifterOperand(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); |
| 2190 __ b(deopt, CS); | 2190 __ b(deopt, CS); |
| 2191 } | 2191 } |
| 2192 // Left is not a constant. | 2192 // Left is not a constant. |
| 2193 // Check if count too large for handling it inlined. | 2193 // Check if count too large for handling it inlined. |
| 2194 __ SmiUntag(right); | 2194 __ Asr(IP, right, kSmiTagSize); // SmiUntag right into IP. |
| 2195 // Overflow test (preserve left and right); | 2195 // Overflow test (preserve left, right, and IP); |
| 2196 __ Lsl(IP, left, right); | 2196 Register temp = locs.temp(0).reg(); |
| 2197 __ cmp(left, ShifterOperand(IP, ASR, right)); | 2197 __ Lsl(temp, left, IP); |
| 2198 __ cmp(left, ShifterOperand(temp, ASR, IP)); |
| 2198 __ b(deopt, NE); // Overflow. | 2199 __ b(deopt, NE); // Overflow. |
| 2199 // Shift for result now we know there is no overflow. | 2200 // Shift for result now we know there is no overflow. |
| 2200 __ Lsl(result, left, right); | 2201 __ Lsl(result, left, IP); |
| 2201 } | 2202 } |
| 2202 } | 2203 } |
| 2203 | 2204 |
| 2204 | 2205 |
| 2205 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 2206 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| 2206 const intptr_t kNumInputs = 2; | 2207 const intptr_t kNumInputs = 2; |
| 2207 const intptr_t kNumTemps = 0; | 2208 const intptr_t kNumTemps = 0; |
| 2208 LocationSummary* summary = | 2209 LocationSummary* summary = |
| 2209 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2210 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2210 if (op_kind() == Token::kTRUNCDIV) { | 2211 if (op_kind() == Token::kTRUNCDIV) { |
| 2212 summary->set_in(0, Location::RequiresRegister()); |
| 2211 if (RightIsPowerOfTwoConstant()) { | 2213 if (RightIsPowerOfTwoConstant()) { |
| 2212 summary->set_in(0, Location::RequiresRegister()); | |
| 2213 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2214 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2214 summary->set_in(1, Location::Constant(right_constant->value())); | 2215 summary->set_in(1, Location::Constant(right_constant->value())); |
| 2215 summary->set_out(Location::RequiresRegister()); | |
| 2216 } else { | 2216 } else { |
| 2217 // Both inputs must be writable because they will be untagged. | 2217 summary->set_in(1, Location::RequiresRegister()); |
| 2218 summary->set_in(0, Location::WritableRegister()); | |
| 2219 summary->set_in(1, Location::WritableRegister()); | |
| 2220 summary->set_out(Location::RequiresRegister()); | |
| 2221 } | 2218 } |
| 2219 summary->AddTemp(Location::RequiresRegister()); |
| 2220 summary->set_out(Location::RequiresRegister()); |
| 2222 return summary; | 2221 return summary; |
| 2223 } | 2222 } |
| 2224 summary->set_in(0, Location::RequiresRegister()); | 2223 summary->set_in(0, Location::RequiresRegister()); |
| 2225 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 2224 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 2225 if (((op_kind() == Token::kSHL) && !is_truncating()) || |
| 2226 (op_kind() == Token::kSHR)) { |
| 2227 summary->AddTemp(Location::RequiresRegister()); |
| 2228 } |
| 2226 // We make use of 3-operand instructions by not requiring result register | 2229 // We make use of 3-operand instructions by not requiring result register |
| 2227 // to be identical to first input register as on Intel. | 2230 // to be identical to first input register as on Intel. |
| 2228 summary->set_out(Location::RequiresRegister()); | 2231 summary->set_out(Location::RequiresRegister()); |
| 2229 return summary; | 2232 return summary; |
| 2230 } | 2233 } |
| 2231 | 2234 |
| 2232 | 2235 |
| 2233 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2236 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2234 if (op_kind() == Token::kSHL) { | 2237 if (op_kind() == Token::kSHL) { |
| 2235 EmitSmiShiftLeft(compiler, this); | 2238 EmitSmiShiftLeft(compiler, this); |
| 2236 return; | 2239 return; |
| 2237 } | 2240 } |
| 2238 | 2241 |
| 2239 ASSERT(!is_truncating()); | 2242 ASSERT(!is_truncating()); |
| 2240 Register left = locs()->in(0).reg(); | 2243 Register left = locs()->in(0).reg(); |
| 2241 Register result = locs()->out().reg(); | 2244 Register result = locs()->out().reg(); |
| 2242 Label* deopt = NULL; | 2245 Label* deopt = NULL; |
| 2243 if (CanDeoptimize()) { | 2246 if (CanDeoptimize()) { |
| 2244 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); | 2247 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); |
| 2245 } | 2248 } |
| 2246 | 2249 |
| 2247 if (locs()->in(1).IsConstant()) { | 2250 if (locs()->in(1).IsConstant()) { |
| 2248 const Object& constant = locs()->in(1).constant(); | 2251 const Object& constant = locs()->in(1).constant(); |
| 2249 ASSERT(constant.IsSmi()); | 2252 ASSERT(constant.IsSmi()); |
| 2250 int32_t imm = reinterpret_cast<int32_t>(constant.raw()); | 2253 int32_t imm = reinterpret_cast<int32_t>(constant.raw()); |
| 2251 switch (op_kind()) { | 2254 switch (op_kind()) { |
| 2252 case Token::kSUB: { | 2255 case Token::kSUB: { |
| 2253 imm = -imm; // TODO(regis): What if deopt != NULL && imm == 0x80000000? | 2256 imm = -imm; // TODO(regis): What if deopt != NULL && imm == 0x80000000? |
| 2254 // Fall through. | 2257 // Fall through. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2298 __ b(deopt, EQ); | 2301 __ b(deopt, EQ); |
| 2299 __ rsb(result, left, ShifterOperand(0)); | 2302 __ rsb(result, left, ShifterOperand(0)); |
| 2300 break; | 2303 break; |
| 2301 } | 2304 } |
| 2302 ASSERT((value != 0) && Utils::IsPowerOfTwo(Utils::Abs(value))); | 2305 ASSERT((value != 0) && Utils::IsPowerOfTwo(Utils::Abs(value))); |
| 2303 const intptr_t shift_count = | 2306 const intptr_t shift_count = |
| 2304 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; | 2307 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; |
| 2305 ASSERT(kSmiTagSize == 1); | 2308 ASSERT(kSmiTagSize == 1); |
| 2306 __ mov(IP, ShifterOperand(left, ASR, 31)); | 2309 __ mov(IP, ShifterOperand(left, ASR, 31)); |
| 2307 ASSERT(shift_count > 1); // 1, -1 case handled above. | 2310 ASSERT(shift_count > 1); // 1, -1 case handled above. |
| 2308 __ add(left, left, ShifterOperand(IP, LSR, 32 - shift_count)); | 2311 Register temp = locs()->temp(0).reg(); |
| 2312 __ add(temp, left, ShifterOperand(IP, LSR, 32 - shift_count)); |
| 2309 ASSERT(shift_count > 0); | 2313 ASSERT(shift_count > 0); |
| 2310 __ mov(result, ShifterOperand(left, ASR, shift_count)); | 2314 __ mov(result, ShifterOperand(temp, ASR, shift_count)); |
| 2311 if (value < 0) { | 2315 if (value < 0) { |
| 2312 __ rsb(result, result, ShifterOperand(0)); | 2316 __ rsb(result, result, ShifterOperand(0)); |
| 2313 } | 2317 } |
| 2314 __ SmiTag(result); | 2318 __ SmiTag(result); |
| 2315 break; | 2319 break; |
| 2316 } | 2320 } |
| 2317 case Token::kBIT_AND: { | 2321 case Token::kBIT_AND: { |
| 2318 // No overflow check. | 2322 // No overflow check. |
| 2319 ShifterOperand shifter_op; | 2323 ShifterOperand shifter_op; |
| 2320 if (ShifterOperand::CanHold(imm, &shifter_op)) { | 2324 if (ShifterOperand::CanHold(imm, &shifter_op)) { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2393 case Token::kSUB: { | 2397 case Token::kSUB: { |
| 2394 if (deopt == NULL) { | 2398 if (deopt == NULL) { |
| 2395 __ sub(result, left, ShifterOperand(right)); | 2399 __ sub(result, left, ShifterOperand(right)); |
| 2396 } else { | 2400 } else { |
| 2397 __ subs(result, left, ShifterOperand(right)); | 2401 __ subs(result, left, ShifterOperand(right)); |
| 2398 __ b(deopt, VS); | 2402 __ b(deopt, VS); |
| 2399 } | 2403 } |
| 2400 break; | 2404 break; |
| 2401 } | 2405 } |
| 2402 case Token::kMUL: { | 2406 case Token::kMUL: { |
| 2403 __ SmiUntag(left); | 2407 __ Asr(IP, left, kSmiTagSize); // SmiUntag left into IP. |
| 2404 if (deopt == NULL) { | 2408 if (deopt == NULL) { |
| 2405 __ mul(result, left, right); | 2409 __ mul(result, IP, right); |
| 2406 } else { | 2410 } else { |
| 2407 __ smull(result, IP, left, right); | 2411 __ smull(result, IP, IP, right); |
| 2408 // IP: result bits 32..63. | 2412 // IP: result bits 32..63. |
| 2409 __ cmp(IP, ShifterOperand(result, ASR, 31)); | 2413 __ cmp(IP, ShifterOperand(result, ASR, 31)); |
| 2410 __ b(deopt, NE); | 2414 __ b(deopt, NE); |
| 2411 } | 2415 } |
| 2412 break; | 2416 break; |
| 2413 } | 2417 } |
| 2414 case Token::kBIT_AND: { | 2418 case Token::kBIT_AND: { |
| 2415 // No overflow check. | 2419 // No overflow check. |
| 2416 __ and_(result, left, ShifterOperand(right)); | 2420 __ and_(result, left, ShifterOperand(right)); |
| 2417 break; | 2421 break; |
| 2418 } | 2422 } |
| 2419 case Token::kBIT_OR: { | 2423 case Token::kBIT_OR: { |
| 2420 // No overflow check. | 2424 // No overflow check. |
| 2421 __ orr(result, left, ShifterOperand(right)); | 2425 __ orr(result, left, ShifterOperand(right)); |
| 2422 break; | 2426 break; |
| 2423 } | 2427 } |
| 2424 case Token::kBIT_XOR: { | 2428 case Token::kBIT_XOR: { |
| 2425 // No overflow check. | 2429 // No overflow check. |
| 2426 __ eor(result, left, ShifterOperand(right)); | 2430 __ eor(result, left, ShifterOperand(right)); |
| 2427 break; | 2431 break; |
| 2428 } | 2432 } |
| 2429 case Token::kTRUNCDIV: { | 2433 case Token::kTRUNCDIV: { |
| 2430 // Handle divide by zero in runtime. | 2434 // Handle divide by zero in runtime. |
| 2431 __ cmp(right, ShifterOperand(0)); | 2435 __ cmp(right, ShifterOperand(0)); |
| 2432 __ b(deopt, EQ); | 2436 __ b(deopt, EQ); |
| 2433 __ SmiUntag(left); | 2437 Register temp = locs()->temp(0).reg(); |
| 2434 __ SmiUntag(right); | 2438 __ Asr(temp, left, kSmiTagSize); // SmiUntag left into temp. |
| 2439 __ Asr(IP, right, kSmiTagSize); // SmiUntag right into IP. |
| 2435 if (!CPUFeatures::integer_division_supported()) { | 2440 if (!CPUFeatures::integer_division_supported()) { |
| 2436 UNIMPLEMENTED(); | 2441 UNIMPLEMENTED(); |
| 2437 } | 2442 } |
| 2438 __ sdiv(result, left, right); | 2443 __ sdiv(result, temp, IP); |
| 2439 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 2444 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 2440 // case we cannot tag the result. | 2445 // case we cannot tag the result. |
| 2441 __ CompareImmediate(result, 0x40000000); | 2446 __ CompareImmediate(result, 0x40000000); |
| 2442 __ b(deopt, EQ); | 2447 __ b(deopt, EQ); |
| 2443 __ SmiTag(result); | 2448 __ SmiTag(result); |
| 2444 break; | 2449 break; |
| 2445 } | 2450 } |
| 2446 case Token::kSHR: { | 2451 case Token::kSHR: { |
| 2447 if (CanDeoptimize()) { | 2452 if (CanDeoptimize()) { |
| 2448 __ CompareImmediate(right, 0); | 2453 __ CompareImmediate(right, 0); |
| 2449 __ b(deopt, LT); | 2454 __ b(deopt, LT); |
| 2450 } | 2455 } |
| 2451 __ SmiUntag(right); | 2456 __ Asr(IP, right, kSmiTagSize); // SmiUntag right into IP. |
| 2452 // sarl operation masks the count to 5 bits. | 2457 // sarl operation masks the count to 5 bits. |
| 2453 const intptr_t kCountLimit = 0x1F; | 2458 const intptr_t kCountLimit = 0x1F; |
| 2454 Range* right_range = this->right()->definition()->range(); | 2459 Range* right_range = this->right()->definition()->range(); |
| 2455 if ((right_range == NULL) || | 2460 if ((right_range == NULL) || |
| 2456 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { | 2461 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { |
| 2457 __ CompareImmediate(right, kCountLimit); | 2462 __ CompareImmediate(IP, kCountLimit); |
| 2458 __ LoadImmediate(right, kCountLimit, GT); | 2463 __ LoadImmediate(IP, kCountLimit, GT); |
| 2459 } | 2464 } |
| 2460 __ SmiUntag(left); | 2465 Register temp = locs()->temp(0).reg(); |
| 2461 __ Asr(result, left, right); | 2466 __ Asr(temp, left, kSmiTagSize); // SmiUntag left into temp. |
| 2467 __ Asr(result, temp, IP); |
| 2462 __ SmiTag(result); | 2468 __ SmiTag(result); |
| 2463 break; | 2469 break; |
| 2464 } | 2470 } |
| 2465 case Token::kDIV: { | 2471 case Token::kDIV: { |
| 2466 // Dispatches to 'Double./'. | 2472 // Dispatches to 'Double./'. |
| 2467 // TODO(srdjan): Implement as conversion to double and double division. | 2473 // TODO(srdjan): Implement as conversion to double and double division. |
| 2468 UNREACHABLE(); | 2474 UNREACHABLE(); |
| 2469 break; | 2475 break; |
| 2470 } | 2476 } |
| 2471 case Token::kMOD: { | 2477 case Token::kMOD: { |
| (...skipping 1140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3612 compiler->GenerateCall(token_pos(), | 3618 compiler->GenerateCall(token_pos(), |
| 3613 &label, | 3619 &label, |
| 3614 PcDescriptors::kOther, | 3620 PcDescriptors::kOther, |
| 3615 locs()); | 3621 locs()); |
| 3616 __ Drop(2); // Discard type arguments and receiver. | 3622 __ Drop(2); // Discard type arguments and receiver. |
| 3617 } | 3623 } |
| 3618 | 3624 |
| 3619 } // namespace dart | 3625 } // namespace dart |
| 3620 | 3626 |
| 3621 #endif // defined TARGET_ARCH_ARM | 3627 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |