Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Side by Side Diff: runtime/vm/intermediate_language_x64.cc

Issue 61123003: Inline integer modulo operation. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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, &not_32bit);
2511 __ movsxd(temp, right);
2512 __ cmpq(temp, right);
2513 __ j(NOT_EQUAL, &not_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(&not_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
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
OLDNEW
« runtime/vm/intermediate_language_ia32.cc ('K') | « runtime/vm/intermediate_language_mips.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698