| Index: runtime/vm/intermediate_language_x64.cc
|
| diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
|
| index afac01fb721262d969ad6a0cda78dfc1d0e6aac5..2dfed3a9f7a38f8d232f285840684f8209e2eb74 100644
|
| --- a/runtime/vm/intermediate_language_x64.cc
|
| +++ b/runtime/vm/intermediate_language_x64.cc
|
| @@ -2328,13 +2328,40 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| break;
|
| }
|
| case Token::kTRUNCDIV: {
|
| - // Handle divide by zero in runtime.
|
| - __ testq(right, right);
|
| - __ j(ZERO, deopt);
|
| + Label not_32bit, done;
|
| +
|
| + Register temp = locs()->temp(0).reg();
|
| ASSERT(left == RAX);
|
| ASSERT((right != RDX) && (right != RAX));
|
| - ASSERT(locs()->temp(0).reg() == RDX);
|
| + ASSERT(temp == RDX);
|
| ASSERT(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.
|
| + __ movsxl(temp, left);
|
| + __ cmpq(temp, left);
|
| + __ j(NOT_EQUAL, ¬_32bit);
|
| + __ movsxl(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);
|
| + __ movsxl(result, result);
|
| + __ jmp(&done);
|
| +
|
| + // Divide using 64bit idiv.
|
| + __ Bind(¬_32bit);
|
| __ SmiUntag(left);
|
| __ SmiUntag(right);
|
| __ cqo(); // Sign extend RAX -> RDX:RAX.
|
| @@ -2343,6 +2370,7 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| // case we cannot tag the result.
|
| __ cmpq(result, Immediate(0x4000000000000000));
|
| __ j(EQUAL, deopt);
|
| + __ Bind(&done);
|
| __ SmiTag(result);
|
| break;
|
| }
|
|
|