| 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 2184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2195 | 2195 |
| 2196 | 2196 |
| 2197 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 2197 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| 2198 const intptr_t kNumInputs = 2; | 2198 const intptr_t kNumInputs = 2; |
| 2199 | 2199 |
| 2200 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2200 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2201 if ((right_constant != NULL) && | 2201 if ((right_constant != NULL) && |
| 2202 (op_kind() != Token::kTRUNCDIV) && | 2202 (op_kind() != Token::kTRUNCDIV) && |
| 2203 (op_kind() != Token::kSHL) && | 2203 (op_kind() != Token::kSHL) && |
| 2204 (op_kind() != Token::kMUL) && | 2204 (op_kind() != Token::kMUL) && |
| 2205 (op_kind() != Token::kMOD) && |
| 2205 CanBeImmediate(right_constant->value())) { | 2206 CanBeImmediate(right_constant->value())) { |
| 2206 const intptr_t kNumTemps = 0; | 2207 const intptr_t kNumTemps = 0; |
| 2207 LocationSummary* summary = | 2208 LocationSummary* summary = |
| 2208 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2209 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2209 summary->set_in(0, Location::RequiresRegister()); | 2210 summary->set_in(0, Location::RequiresRegister()); |
| 2210 summary->set_in(1, Location::Constant(right_constant->value())); | 2211 summary->set_in(1, Location::Constant(right_constant->value())); |
| 2211 summary->set_out(Location::SameAsFirstInput()); | 2212 summary->set_out(Location::SameAsFirstInput()); |
| 2212 return summary; | 2213 return summary; |
| 2213 } | 2214 } |
| 2214 | 2215 |
| 2215 if (op_kind() == Token::kTRUNCDIV) { | 2216 if (op_kind() == Token::kTRUNCDIV) { |
| 2216 const intptr_t kNumTemps = 1; | 2217 const intptr_t kNumTemps = 1; |
| 2217 LocationSummary* summary = | 2218 LocationSummary* summary = |
| 2218 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2219 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2219 if (RightIsPowerOfTwoConstant()) { | 2220 if (RightIsPowerOfTwoConstant()) { |
| 2220 summary->set_in(0, Location::RequiresRegister()); | 2221 summary->set_in(0, Location::RequiresRegister()); |
| 2221 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2222 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2222 summary->set_in(1, Location::Constant(right_constant->value())); | 2223 summary->set_in(1, Location::Constant(right_constant->value())); |
| 2223 summary->set_temp(0, Location::RequiresRegister()); | 2224 summary->set_temp(0, Location::RequiresRegister()); |
| 2224 summary->set_out(Location::SameAsFirstInput()); | 2225 summary->set_out(Location::SameAsFirstInput()); |
| 2225 } else { | 2226 } else { |
| 2226 // Both inputs must be writable because they will be untagged. | 2227 // Both inputs must be writable because they will be untagged. |
| 2227 summary->set_in(0, Location::RegisterLocation(RAX)); | 2228 summary->set_in(0, Location::RegisterLocation(RAX)); |
| 2228 summary->set_in(1, Location::WritableRegister()); | 2229 summary->set_in(1, Location::WritableRegister()); |
| 2229 summary->set_out(Location::SameAsFirstInput()); | 2230 summary->set_out(Location::SameAsFirstInput()); |
| 2230 // Will be used for sign extension and division. | 2231 // Will be used for sign extension and division. |
| 2231 summary->set_temp(0, Location::RegisterLocation(RDX)); | 2232 summary->set_temp(0, Location::RegisterLocation(RDX)); |
| 2232 } | 2233 } |
| 2233 return summary; | 2234 return summary; |
| 2235 } else if (op_kind() == Token::kMOD) { |
| 2236 const intptr_t kNumTemps = 1; |
| 2237 LocationSummary* summary = |
| 2238 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2239 // Both inputs must be writable because they will be untagged. |
| 2240 summary->set_in(0, Location::RegisterLocation(RDX)); |
| 2241 summary->set_in(1, Location::WritableRegister()); |
| 2242 summary->set_out(Location::SameAsFirstInput()); |
| 2243 // Will be used for sign extension and division. |
| 2244 summary->set_temp(0, Location::RegisterLocation(RAX)); |
| 2245 return summary; |
| 2234 } else if (op_kind() == Token::kSHR) { | 2246 } else if (op_kind() == Token::kSHR) { |
| 2235 const intptr_t kNumTemps = 0; | 2247 const intptr_t kNumTemps = 0; |
| 2236 LocationSummary* summary = | 2248 LocationSummary* summary = |
| 2237 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2249 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2238 summary->set_in(0, Location::RequiresRegister()); | 2250 summary->set_in(0, Location::RequiresRegister()); |
| 2239 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); | 2251 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); |
| 2240 summary->set_out(Location::SameAsFirstInput()); | 2252 summary->set_out(Location::SameAsFirstInput()); |
| 2241 return summary; | 2253 return summary; |
| 2242 } else if (op_kind() == Token::kSHL) { | 2254 } else if (op_kind() == Token::kSHL) { |
| 2243 const intptr_t kNumTemps = 0; | 2255 const intptr_t kNumTemps = 0; |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2508 __ cqo(); // Sign extend RAX -> RDX:RAX. | 2520 __ cqo(); // Sign extend RAX -> RDX:RAX. |
| 2509 __ idivq(right); // RAX: quotient, RDX: remainder. | 2521 __ idivq(right); // RAX: quotient, RDX: remainder. |
| 2510 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 2522 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 2511 // case we cannot tag the result. | 2523 // case we cannot tag the result. |
| 2512 __ CompareImmediate(result, Immediate(0x4000000000000000), PP); | 2524 __ CompareImmediate(result, Immediate(0x4000000000000000), PP); |
| 2513 __ j(EQUAL, deopt); | 2525 __ j(EQUAL, deopt); |
| 2514 __ Bind(&done); | 2526 __ Bind(&done); |
| 2515 __ SmiTag(result); | 2527 __ SmiTag(result); |
| 2516 break; | 2528 break; |
| 2517 } | 2529 } |
| 2530 case Token::kMOD: { |
| 2531 Label not_32bit, div_done; |
| 2532 |
| 2533 Register temp = locs()->temp(0).reg(); |
| 2534 ASSERT(left == RDX); |
| 2535 ASSERT((right != RDX) && (right != RAX)); |
| 2536 ASSERT(temp == RAX); |
| 2537 ASSERT(result == RDX); |
| 2538 // Handle divide by zero in runtime. |
| 2539 __ testq(right, right); |
| 2540 __ j(ZERO, deopt); |
| 2541 // Check if both operands fit into 32bits as idiv with 64bit operands |
| 2542 // requires twice as many cycles and has much higher latency. |
| 2543 // We are checking this before untagging them to avoid corner case |
| 2544 // dividing INT_MAX by -1 that raises exception because quotient is |
| 2545 // too large for 32bit register. |
| 2546 __ movsxd(temp, left); |
| 2547 __ cmpq(temp, left); |
| 2548 __ j(NOT_EQUAL, ¬_32bit); |
| 2549 __ movsxd(temp, right); |
| 2550 __ cmpq(temp, right); |
| 2551 __ j(NOT_EQUAL, ¬_32bit); |
| 2552 // Both operands are 31bit smis. Divide using 32bit idiv. |
| 2553 __ SmiUntag(left); |
| 2554 __ SmiUntag(right); |
| 2555 __ movq(RAX, RDX); |
| 2556 __ cdq(); |
| 2557 __ idivl(right); |
| 2558 __ movsxd(result, result); |
| 2559 __ jmp(&div_done); |
| 2560 |
| 2561 // Divide using 64bit idiv. |
| 2562 __ Bind(¬_32bit); |
| 2563 __ SmiUntag(left); |
| 2564 __ SmiUntag(right); |
| 2565 __ movq(RAX, RDX); |
| 2566 __ cqo(); // Sign extend RAX -> RDX:RAX. |
| 2567 __ idivq(right); // RAX: quotient, RDX: remainder. |
| 2568 __ Bind(&div_done); |
| 2569 // res = left % right; |
| 2570 // if (res < 0) { |
| 2571 // if (right < 0) { |
| 2572 // res = res - right; |
| 2573 // } else { |
| 2574 // res = res + right; |
| 2575 // } |
| 2576 // } |
| 2577 Label subtract, all_done; |
| 2578 __ cmpq(result, Immediate(0)); |
| 2579 __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); |
| 2580 // Result is negative, adjust it. |
| 2581 __ cmpq(right, Immediate(0)); |
| 2582 __ j(LESS, &subtract, Assembler::kNearJump); |
| 2583 __ addq(result, right); |
| 2584 __ jmp(&all_done, Assembler::kNearJump); |
| 2585 __ Bind(&subtract); |
| 2586 __ subq(result, right); |
| 2587 __ Bind(&all_done); |
| 2588 __ SmiTag(result); |
| 2589 break; |
| 2590 } |
| 2518 case Token::kSHR: { | 2591 case Token::kSHR: { |
| 2519 if (CanDeoptimize()) { | 2592 if (CanDeoptimize()) { |
| 2520 __ CompareImmediate(right, Immediate(0), PP); | 2593 __ CompareImmediate(right, Immediate(0), PP); |
| 2521 __ j(LESS, deopt); | 2594 __ j(LESS, deopt); |
| 2522 } | 2595 } |
| 2523 __ SmiUntag(right); | 2596 __ SmiUntag(right); |
| 2524 // sarq operation masks the count to 6 bits. | 2597 // sarq operation masks the count to 6 bits. |
| 2525 const intptr_t kCountLimit = 0x3F; | 2598 const intptr_t kCountLimit = 0x3F; |
| 2526 Range* right_range = this->right()->definition()->range(); | 2599 Range* right_range = this->right()->definition()->range(); |
| 2527 if ((right_range == NULL) || | 2600 if ((right_range == NULL) || |
| 2528 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { | 2601 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) { |
| 2529 __ CompareImmediate(right, Immediate(kCountLimit), PP); | 2602 __ CompareImmediate(right, Immediate(kCountLimit), PP); |
| 2530 Label count_ok; | 2603 Label count_ok; |
| 2531 __ j(LESS, &count_ok, Assembler::kNearJump); | 2604 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 2532 __ LoadImmediate(right, Immediate(kCountLimit), PP); | 2605 __ LoadImmediate(right, Immediate(kCountLimit), PP); |
| 2533 __ Bind(&count_ok); | 2606 __ Bind(&count_ok); |
| 2534 } | 2607 } |
| 2535 ASSERT(right == RCX); // Count must be in RCX | 2608 ASSERT(right == RCX); // Count must be in RCX |
| 2536 __ SmiUntag(left); | 2609 __ SmiUntag(left); |
| 2537 __ sarq(left, right); | 2610 __ sarq(left, right); |
| 2538 __ SmiTag(left); | 2611 __ SmiTag(left); |
| 2539 break; | 2612 break; |
| 2540 } | 2613 } |
| 2541 case Token::kDIV: { | 2614 case Token::kDIV: { |
| 2542 // Dispatches to 'Double./'. | 2615 // Dispatches to 'Double./'. |
| 2543 // TODO(srdjan): Implement as conversion to double and double division. | 2616 // TODO(srdjan): Implement as conversion to double and double division. |
| 2544 UNREACHABLE(); | 2617 UNREACHABLE(); |
| 2545 break; | 2618 break; |
| 2546 } | 2619 } |
| 2547 case Token::kMOD: { | |
| 2548 // TODO(srdjan): Implement. | |
| 2549 UNREACHABLE(); | |
| 2550 break; | |
| 2551 } | |
| 2552 case Token::kOR: | 2620 case Token::kOR: |
| 2553 case Token::kAND: { | 2621 case Token::kAND: { |
| 2554 // Flow graph builder has dissected this operation to guarantee correct | 2622 // Flow graph builder has dissected this operation to guarantee correct |
| 2555 // behavior (short-circuit evaluation). | 2623 // behavior (short-circuit evaluation). |
| 2556 UNREACHABLE(); | 2624 UNREACHABLE(); |
| 2557 break; | 2625 break; |
| 2558 } | 2626 } |
| 2559 default: | 2627 default: |
| 2560 UNREACHABLE(); | 2628 UNREACHABLE(); |
| 2561 break; | 2629 break; |
| (...skipping 2016 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4578 PcDescriptors::kOther, | 4646 PcDescriptors::kOther, |
| 4579 locs()); | 4647 locs()); |
| 4580 __ Drop(2); // Discard type arguments and receiver. | 4648 __ Drop(2); // Discard type arguments and receiver. |
| 4581 } | 4649 } |
| 4582 | 4650 |
| 4583 } // namespace dart | 4651 } // namespace dart |
| 4584 | 4652 |
| 4585 #undef __ | 4653 #undef __ |
| 4586 | 4654 |
| 4587 #endif // defined TARGET_ARCH_X64 | 4655 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |