Chromium Code Reviews| Index: runtime/vm/intermediate_language_x64.cc |
| =================================================================== |
| --- runtime/vm/intermediate_language_x64.cc (revision 30236) |
| +++ runtime/vm/intermediate_language_x64.cc (working copy) |
| @@ -2187,6 +2187,7 @@ |
| (op_kind() != Token::kSHL) && |
| (op_kind() != Token::kMUL) && |
| (op_kind() != Token::kMOD) && |
| + (op_kind() != Token::kTRUNCDIVMOD) && |
| CanBeImmediate(right_constant->value())) { |
| const intptr_t kNumTemps = 0; |
| LocationSummary* summary = |
| @@ -2216,6 +2217,17 @@ |
| summary->set_temp(0, Location::RegisterLocation(RDX)); |
| } |
| return summary; |
| + } else if (op_kind() == Token::kTRUNCDIVMOD) { |
| + const intptr_t kNumTemps = 1; |
| + LocationSummary* summary = |
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + // Both inputs must be writable because they will be untagged. |
| + summary->set_in(0, Location::RegisterLocation(RAX)); |
| + summary->set_in(1, Location::WritableRegister()); |
| + summary->set_out(Location::RequiresRegister()); |
| + // Will be used for sign extension and division. |
| + summary->set_temp(0, Location::RegisterLocation(RDX)); |
| + return summary; |
| } else if (op_kind() == Token::kMOD) { |
| const intptr_t kNumTemps = 1; |
| LocationSummary* summary = |
| @@ -2271,7 +2283,8 @@ |
| ASSERT(!is_truncating()); |
| Register left = locs()->in(0).reg(); |
| Register result = locs()->out().reg(); |
| - ASSERT(left == result); |
| + // DIVMOD is different. |
| + ASSERT((op_kind() == Token::kTRUNCDIVMOD) || (left == result)); |
| Label* deopt = NULL; |
| if (CanDeoptimize()) { |
| deopt = compiler->AddDeoptStub(deopt_id(), |
| @@ -2572,6 +2585,89 @@ |
| __ SmiTag(result); |
| break; |
| } |
| + case Token::kTRUNCDIVMOD: { |
|
Florian Schneider
2013/11/14 10:17:44
I'm not sure how much making this operation a Bina
srdjan
2013/11/20 21:41:47
Created new instructions as suggested.
|
| + Label not_32bit, done; |
| + Register temp = locs()->temp(0).reg(); |
| + ASSERT(left == RAX); |
| + ASSERT((right != RDX) && (right != RAX)); |
| + ASSERT(temp == RDX); |
| + ASSERT((result != RDX) && (result != RAX)); |
| + // Handle divide by zero in runtime. |
| + __ testq(right, right); |
| + __ j(ZERO, deopt); |
| + // Check if both operands fit into 32bits as idiv with 64bit operands |
| + // requires twice as many cycles and has much higher latency. |
| + // We are checking this before untagging them to avoid corner case |
| + // dividing INT_MAX by -1 that raises exception because quotient is |
| + // too large for 32bit register. |
| + __ movsxd(temp, left); |
| + __ cmpq(temp, left); |
| + __ j(NOT_EQUAL, ¬_32bit); |
| + __ movsxd(temp, right); |
| + __ cmpq(temp, right); |
| + __ j(NOT_EQUAL, ¬_32bit); |
| + |
| + // Both operands are 31bit smis. Divide using 32bit idiv. |
| + __ SmiUntag(left); |
| + __ SmiUntag(right); |
| + __ cdq(); |
| + __ idivl(right); |
| + __ movsxd(RAX, RAX); |
| + __ movsxd(RDX, RDX); |
| + __ jmp(&done); |
| + |
| + // Divide using 64bit idiv. |
| + __ Bind(¬_32bit); |
| + __ SmiUntag(left); |
| + __ SmiUntag(right); |
| + __ cqo(); // Sign extend RAX -> RDX:RAX. |
| + __ idivq(right); // RAX: quotient, RDX: remainder. |
| + // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| + // case we cannot tag the result. |
| + __ CompareImmediate(RAX, Immediate(0x4000000000000000), PP); |
| + __ j(EQUAL, deopt); |
| + __ Bind(&done); |
| + |
| + // Modulo correction (RDX). |
| + // res = left % right; |
| + // if (res < 0) { |
| + // if (right < 0) { |
| + // res = res - right; |
| + // } else { |
| + // res = res + right; |
| + // } |
| + // } |
| + Label subtract, all_done; |
| + __ cmpq(RDX, Immediate(0)); |
| + __ j(GREATER_EQUAL, &all_done, Assembler::kNearJump); |
| + // Result is negative, adjust it. |
| + __ cmpq(right, Immediate(0)); |
| + __ j(LESS, &subtract, Assembler::kNearJump); |
| + __ addq(RDX, right); |
| + __ jmp(&all_done, Assembler::kNearJump); |
| + __ Bind(&subtract); |
| + __ subq(RDX, right); |
| + __ Bind(&all_done); |
| + __ SmiTag(result); |
| + |
| + __ LoadObject(result, Array::ZoneHandle(Array::New(2, Heap::kOld)), PP); |
| + const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid); |
| + Address trunc_div_address( |
| + FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid, |
| + index_scale, |
| + result, |
| + 0)); |
| + Address mod_address( |
| + FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid, |
| + index_scale, |
| + result, |
| + 1)); |
| + __ SmiTag(RAX); |
| + __ SmiTag(RDX); |
| + __ StoreIntoObjectNoBarrier(result, trunc_div_address, RAX); |
| + __ StoreIntoObjectNoBarrier(result, mod_address, RDX); |
| + break; |
| + } |
| case Token::kSHR: { |
| if (CanDeoptimize()) { |
| __ CompareImmediate(right, Immediate(0), PP); |