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_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 "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 2146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2157 | 2157 |
| 2158 | 2158 |
| 2159 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 2159 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| 2160 const intptr_t kNumInputs = 2; | 2160 const intptr_t kNumInputs = 2; |
| 2161 | 2161 |
| 2162 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2162 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2163 if ((right_constant != NULL) && | 2163 if ((right_constant != NULL) && |
| 2164 (op_kind() != Token::kTRUNCDIV) && | 2164 (op_kind() != Token::kTRUNCDIV) && |
| 2165 (op_kind() != Token::kSHL) && | 2165 (op_kind() != Token::kSHL) && |
| 2166 (op_kind() != Token::kMUL) && | 2166 (op_kind() != Token::kMUL) && |
| 2167 (op_kind() != Token::kMOD) && | |
| 2167 CanBeImmediate(right_constant->value())) { | 2168 CanBeImmediate(right_constant->value())) { |
| 2168 const intptr_t kNumTemps = 0; | 2169 const intptr_t kNumTemps = 0; |
| 2169 LocationSummary* summary = | 2170 LocationSummary* summary = |
| 2170 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2171 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2171 summary->set_in(0, Location::RequiresRegister()); | 2172 summary->set_in(0, Location::RequiresRegister()); |
| 2172 summary->set_in(1, Location::Constant(right_constant->value())); | 2173 summary->set_in(1, Location::Constant(right_constant->value())); |
| 2173 summary->set_out(Location::SameAsFirstInput()); | 2174 summary->set_out(Location::SameAsFirstInput()); |
| 2174 return summary; | 2175 return summary; |
| 2175 } | 2176 } |
| 2176 | 2177 |
| 2177 if (op_kind() == Token::kTRUNCDIV) { | 2178 if (op_kind() == Token::kTRUNCDIV) { |
| 2178 const intptr_t kNumTemps = 1; | 2179 const intptr_t kNumTemps = 1; |
| 2179 LocationSummary* summary = | 2180 LocationSummary* summary = |
| 2180 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2181 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2181 if (RightIsPowerOfTwoConstant()) { | 2182 if (RightIsPowerOfTwoConstant()) { |
| 2182 summary->set_in(0, Location::RequiresRegister()); | 2183 summary->set_in(0, Location::RequiresRegister()); |
| 2183 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2184 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2184 summary->set_in(1, Location::Constant(right_constant->value())); | 2185 summary->set_in(1, Location::Constant(right_constant->value())); |
| 2185 summary->set_temp(0, Location::RequiresRegister()); | 2186 summary->set_temp(0, Location::RequiresRegister()); |
| 2186 summary->set_out(Location::SameAsFirstInput()); | 2187 summary->set_out(Location::SameAsFirstInput()); |
| 2187 } else { | 2188 } else { |
| 2188 // Both inputs must be writable because they will be untagged. | 2189 // Both inputs must be writable because they will be untagged. |
| 2189 summary->set_in(0, Location::RegisterLocation(RAX)); | 2190 summary->set_in(0, Location::RegisterLocation(RAX)); |
| 2190 summary->set_in(1, Location::WritableRegister()); | 2191 summary->set_in(1, Location::WritableRegister()); |
| 2191 summary->set_out(Location::SameAsFirstInput()); | 2192 summary->set_out(Location::SameAsFirstInput()); |
| 2192 // Will be used for sign extension and division. | 2193 // Will be used for sign extension and division. |
| 2193 summary->set_temp(0, Location::RegisterLocation(RDX)); | 2194 summary->set_temp(0, Location::RegisterLocation(RDX)); |
| 2194 } | 2195 } |
| 2195 return summary; | 2196 return summary; |
| 2197 } else if (op_kind() == Token::kMOD) { | |
| 2198 const intptr_t kNumTemps = 1; | |
| 2199 LocationSummary* summary = | |
| 2200 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 2201 // Both inputs must be writable because they will be untagged. | |
| 2202 summary->set_in(0, Location::RegisterLocation(RDX)); | |
| 2203 summary->set_in(1, Location::WritableRegister()); | |
| 2204 summary->set_out(Location::SameAsFirstInput()); | |
| 2205 // Will be used for sign extension and division. | |
| 2206 summary->set_temp(0, Location::RegisterLocation(RAX)); | |
| 2207 return summary; | |
| 2196 } else if (op_kind() == Token::kSHR) { | 2208 } else if (op_kind() == Token::kSHR) { |
| 2197 const intptr_t kNumTemps = 0; | 2209 const intptr_t kNumTemps = 0; |
| 2198 LocationSummary* summary = | 2210 LocationSummary* summary = |
| 2199 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2211 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2200 summary->set_in(0, Location::RequiresRegister()); | 2212 summary->set_in(0, Location::RequiresRegister()); |
| 2201 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); | 2213 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); |
| 2202 summary->set_out(Location::SameAsFirstInput()); | 2214 summary->set_out(Location::SameAsFirstInput()); |
| 2203 return summary; | 2215 return summary; |
| 2204 } else if (op_kind() == Token::kSHL) { | 2216 } else if (op_kind() == Token::kSHL) { |
| 2205 const intptr_t kNumTemps = 0; | 2217 const intptr_t kNumTemps = 0; |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2470 __ cqo(); // Sign extend RAX -> RDX:RAX. | 2482 __ cqo(); // Sign extend RAX -> RDX:RAX. |
| 2471 __ idivq(right); // RAX: quotient, RDX: remainder. | 2483 __ idivq(right); // RAX: quotient, RDX: remainder. |
| 2472 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 2484 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 2473 // case we cannot tag the result. | 2485 // case we cannot tag the result. |
| 2474 __ CompareImmediate(result, Immediate(0x4000000000000000), PP); | 2486 __ CompareImmediate(result, Immediate(0x4000000000000000), PP); |
| 2475 __ j(EQUAL, deopt); | 2487 __ j(EQUAL, deopt); |
| 2476 __ Bind(&done); | 2488 __ Bind(&done); |
| 2477 __ SmiTag(result); | 2489 __ SmiTag(result); |
| 2478 break; | 2490 break; |
| 2479 } | 2491 } |
| 2492 case Token::kMOD: { | |
| 2493 Label not_32bit, div_done; | |
| 2494 | |
| 2495 Register temp = locs()->temp(0).reg(); | |
| 2496 ASSERT(left == RDX); | |
| 2497 ASSERT((right != RDX) && (right != RAX)); | |
| 2498 ASSERT(temp == RAX); | |
| 2499 ASSERT(result == RDX); | |
| 2500 // Handle divide by zero in runtime. | |
| 2501 __ testq(right, right); | |
| 2502 __ j(ZERO, deopt); | |
| 2503 // Check if both operands fit into 32bits as idiv with 64bit operands | |
| 2504 // requires twice as many cycles and has much higher latency. | |
| 2505 // We are checking this before untagging them to avoid corner case | |
| 2506 // dividing INT_MAX by -1 that raises exception because quotient is | |
| 2507 // too large for 32bit register. | |
| 2508 __ movsxd(temp, left); | |
| 2509 __ cmpq(temp, left); | |
| 2510 __ j(NOT_EQUAL, ¬_32bit); | |
| 2511 __ movsxd(temp, right); | |
| 2512 __ cmpq(temp, right); | |
| 2513 __ j(NOT_EQUAL, ¬_32bit); | |
| 2514 // Both operands are 31bit smis. Divide using 32bit idiv. | |
| 2515 __ SmiUntag(left); | |
| 2516 __ SmiUntag(right); | |
| 2517 __ movq(RAX, RDX); | |
| 2518 __ cdq(); | |
| 2519 __ idivl(right); | |
| 2520 __ movsxd(result, result); | |
| 2521 __ jmp(&div_done); | |
| 2522 | |
| 2523 // Divide using 64bit idiv. | |
| 2524 __ Bind(¬_32bit); | |
| 2525 __ SmiUntag(left); | |
| 2526 __ SmiUntag(right); | |
| 2527 __ movq(RAX, RDX); | |
| 2528 __ cqo(); // Sign extend RAX -> RDX:RAX. | |
| 2529 __ idivq(right); // RAX: quotient, RDX: remainder. | |
| 2530 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | |
| 2531 // case we cannot tag the result. | |
| 2532 __ CompareImmediate(result, Immediate(0x4000000000000000), PP); | |
|
zra
2013/11/07 16:40:06
I couldn't find an existing test for this case. Is
srdjan
2013/11/07 21:26:10
Copy and paste error, removing. The other architec
| |
| 2533 __ j(EQUAL, deopt); | |
| 2534 __ Bind(&div_done); | |
| 2535 // res = left % right; | |
| 2536 // if (res < 0) { | |
| 2537 // if (right < 0) { | |
| 2538 // res = res - right; | |
| 2539 // } else { | |
| 2540 // res = res + right; | |
| 2541 // } | |
| 2542 // } | |
| 2543 Label subtract, all_done; | |
| 2544 __ cmpq(result, Immediate(0)); | |
| 2545 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); | |
| 2546 // Result is negative, adjust it. | |
| 2547 __ cmpq(right, Immediate(0)); | |
| 2548 __ j(LESS, &subtract, Assembler::kNearJump); | |
| 2549 __ addq(result, right); | |
| 2550 __ jmp(&all_done, Assembler::kNearJump); | |
| 2551 __ Bind(&subtract); | |
| 2552 __ subq(result, right); | |
| 2553 __ Bind(&all_done); | |
| 2554 __ SmiTag(result); | |
| 2555 break; | |
| 2556 } | |
| 2480 case Token::kSHR: { | 2557 case Token::kSHR: { |
| 2481 if (CanDeoptimize()) { | 2558 if (CanDeoptimize()) { |
| 2482 __ CompareImmediate(right, Immediate(0), PP); | 2559 __ CompareImmediate(right, Immediate(0), PP); |
| 2483 __ j(LESS, deopt); | 2560 __ j(LESS, deopt); |
| 2484 } | 2561 } |
| 2485 __ SmiUntag(right); | 2562 __ SmiUntag(right); |
| 2486 // sarq operation masks the count to 6 bits. | 2563 // sarq operation masks the count to 6 bits. |
| 2487 const intptr_t kCountLimit = 0x3F; | 2564 const intptr_t kCountLimit = 0x3F; |
| 2488 Range* right_range = this->right()->definition()->range(); | 2565 Range* right_range = this->right()->definition()->range(); |
| 2489 if ((right_range == NULL) || | 2566 if ((right_range == NULL) || |
| 2490 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { | 2567 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { |
| 2491 __ CompareImmediate(right, Immediate(kCountLimit), PP); | 2568 __ CompareImmediate(right, Immediate(kCountLimit), PP); |
| 2492 Label count_ok; | 2569 Label count_ok; |
| 2493 __ j(LESS, &count_ok, Assembler::kNearJump); | 2570 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 2494 __ LoadImmediate(right, Immediate(kCountLimit), PP); | 2571 __ LoadImmediate(right, Immediate(kCountLimit), PP); |
| 2495 __ Bind(&count_ok); | 2572 __ Bind(&count_ok); |
| 2496 } | 2573 } |
| 2497 ASSERT(right == RCX); // Count must be in RCX | 2574 ASSERT(right == RCX); // Count must be in RCX |
| 2498 __ SmiUntag(left); | 2575 __ SmiUntag(left); |
| 2499 __ sarq(left, right); | 2576 __ sarq(left, right); |
| 2500 __ SmiTag(left); | 2577 __ SmiTag(left); |
| 2501 break; | 2578 break; |
| 2502 } | 2579 } |
| 2503 case Token::kDIV: { | 2580 case Token::kDIV: { |
| 2504 // Dispatches to 'Double./'. | 2581 // Dispatches to 'Double./'. |
| 2505 // TODO(srdjan): Implement as conversion to double and double division. | 2582 // TODO(srdjan): Implement as conversion to double and double division. |
| 2506 UNREACHABLE(); | 2583 UNREACHABLE(); |
| 2507 break; | 2584 break; |
| 2508 } | 2585 } |
| 2509 case Token::kMOD: { | |
| 2510 // TODO(srdjan): Implement. | |
| 2511 UNREACHABLE(); | |
| 2512 break; | |
| 2513 } | |
| 2514 case Token::kOR: | 2586 case Token::kOR: |
| 2515 case Token::kAND: { | 2587 case Token::kAND: { |
| 2516 // Flow graph builder has dissected this operation to guarantee correct | 2588 // Flow graph builder has dissected this operation to guarantee correct |
| 2517 // behavior (short-circuit evaluation). | 2589 // behavior (short-circuit evaluation). |
| 2518 UNREACHABLE(); | 2590 UNREACHABLE(); |
| 2519 break; | 2591 break; |
| 2520 } | 2592 } |
| 2521 default: | 2593 default: |
| 2522 UNREACHABLE(); | 2594 UNREACHABLE(); |
| 2523 break; | 2595 break; |
| (...skipping 2030 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4554 PcDescriptors::kOther, | 4626 PcDescriptors::kOther, |
| 4555 locs()); | 4627 locs()); |
| 4556 __ Drop(2); // Discard type arguments and receiver. | 4628 __ Drop(2); // Discard type arguments and receiver. |
| 4557 } | 4629 } |
| 4558 | 4630 |
| 4559 } // namespace dart | 4631 } // namespace dart |
| 4560 | 4632 |
| 4561 #undef __ | 4633 #undef __ |
| 4562 | 4634 |
| 4563 #endif // defined TARGET_ARCH_X64 | 4635 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |