| Index: runtime/vm/intrinsifier_x64.cc
|
| ===================================================================
|
| --- runtime/vm/intrinsifier_x64.cc (revision 21658)
|
| +++ runtime/vm/intrinsifier_x64.cc (working copy)
|
| @@ -560,7 +560,7 @@
|
| __ movq(RCX, Address(RSP, + 2 * kWordSize));
|
| __ orq(RCX, RAX);
|
| __ testq(RCX, Immediate(kSmiTagMask));
|
| - __ j(NOT_ZERO, not_smi, Assembler::kNearJump);
|
| + __ j(NOT_ZERO, not_smi);
|
| }
|
|
|
|
|
| @@ -631,30 +631,37 @@
|
| }
|
|
|
|
|
| -bool Intrinsifier::Integer_modulo(Assembler* assembler) {
|
| - Label fall_through, return_zero, try_modulo, not_32bit;
|
| - TestBothArgumentsSmis(assembler, &fall_through);
|
| - // RAX: right argument (divisor)
|
| - // Check if modulo by zero -> exception thrown in main function.
|
| +// Optimizations:
|
| +// - result is 0 if:
|
| +// - left is 0
|
| +// - left equals right
|
| +// - result is left if
|
| +// - left > 0 && left < right
|
| +// RAX: Tagged left (dividend).
|
| +// RCX: Tagged right (divisor).
|
| +// RAX: Untagged result (remainder).
|
| +void EmitRemainderOperation(Assembler* assembler) {
|
| + Label return_zero, try_modulo, not_32bit, done;
|
| + // Check for quick zero results.
|
| __ cmpq(RAX, Immediate(0));
|
| - __ j(EQUAL, &fall_through, Assembler::kNearJump);
|
| - __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend).
|
| - __ cmpq(RCX, Immediate(0));
|
| - __ j(LESS, &fall_through, Assembler::kNearJump);
|
| - __ cmpq(RCX, RAX);
|
| __ j(EQUAL, &return_zero, Assembler::kNearJump);
|
| - __ j(GREATER, &try_modulo, Assembler::kNearJump);
|
| - __ movq(RAX, RCX); // Return dividend as it is smaller than divisor.
|
| + __ cmpq(RAX, RCX);
|
| + __ j(EQUAL, &return_zero, Assembler::kNearJump);
|
| +
|
| + // Check if result equals left.
|
| + __ cmpq(RAX, Immediate(0));
|
| + __ j(LESS, &try_modulo, Assembler::kNearJump);
|
| + // left is positive.
|
| + __ cmpq(RAX, RCX);
|
| + __ j(GREATER, &try_modulo, Assembler::kNearJump);
|
| + // left is less than right, result is left (RAX).
|
| __ ret();
|
|
|
| __ Bind(&return_zero);
|
| - __ xorq(RAX, RAX); // Return zero.
|
| + __ xorq(RAX, RAX);
|
| __ ret();
|
|
|
| __ Bind(&try_modulo);
|
| - // RAX: right (non-null divisor).
|
| - __ movq(RCX, RAX);
|
| - __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend).
|
|
|
| // 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
|
| @@ -662,10 +669,10 @@
|
| // raises exception because quotient is too large for 32bit register.
|
| __ movsxd(RBX, RAX);
|
| __ cmpq(RBX, RAX);
|
| - __ j(NOT_EQUAL, ¬_32bit);
|
| + __ j(NOT_EQUAL, ¬_32bit, Assembler::kNearJump);
|
| __ movsxd(RBX, RCX);
|
| __ cmpq(RBX, RCX);
|
| - __ j(NOT_EQUAL, ¬_32bit);
|
| + __ j(NOT_EQUAL, ¬_32bit, Assembler::kNearJump);
|
|
|
| // Both operands are 31bit smis. Divide using 32bit idiv.
|
| __ SmiUntag(RAX);
|
| @@ -673,8 +680,7 @@
|
| __ cdq();
|
| __ idivl(RCX);
|
| __ movsxd(RAX, RDX);
|
| - __ SmiTag(RAX);
|
| - __ ret();
|
| + __ jmp(&done);
|
|
|
| // Divide using 64bit idiv.
|
| __ Bind(¬_32bit);
|
| @@ -683,14 +689,75 @@
|
| __ cqo();
|
| __ idivq(RCX);
|
| __ movq(RAX, RDX);
|
| + __ Bind(&done);
|
| +}
|
| +
|
| +
|
| +// Implementation:
|
| +// res = left % right;
|
| +// if (res < 0) {
|
| +// if (right < 0) {
|
| +// res = res - right;
|
| +// } else {
|
| +// res = res + right;
|
| +// }
|
| +// }
|
| +bool Intrinsifier::Integer_modulo(Assembler* assembler) {
|
| + Label fall_through, negative_result;
|
| + TestBothArgumentsSmis(assembler, &fall_through);
|
| + // RAX: right argument (divisor)
|
| + __ movq(RCX, RAX);
|
| + __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend).
|
| + // RAX: Tagged left (dividend).
|
| + // RCX: Tagged right (divisor).
|
| + __ cmpq(RCX, Immediate(0));
|
| + __ j(EQUAL, &fall_through);
|
| + EmitRemainderOperation(assembler);
|
| + // Untagged remainder result in RAX.
|
| + __ cmpq(RAX, Immediate(0));
|
| + __ j(LESS, &negative_result, Assembler::kNearJump);
|
| __ SmiTag(RAX);
|
| __ ret();
|
|
|
| + __ Bind(&negative_result);
|
| + Label subtract;
|
| + // RAX: Untagged result.
|
| + // RCX: Untagged right.
|
| + __ cmpq(RCX, Immediate(0));
|
| + __ j(LESS, &subtract, Assembler::kNearJump);
|
| + __ addq(RAX, RCX);
|
| + __ SmiTag(RAX);
|
| + __ ret();
|
| +
|
| + __ Bind(&subtract);
|
| + __ subq(RAX, RCX);
|
| + __ SmiTag(RAX);
|
| + __ ret();
|
| +
|
| __ Bind(&fall_through);
|
| return false;
|
| }
|
|
|
|
|
| +bool Intrinsifier::Integer_remainder(Assembler* assembler) {
|
| + Label fall_through;
|
| + TestBothArgumentsSmis(assembler, &fall_through);
|
| + // RAX: right argument (divisor)
|
| + __ movq(RCX, RAX);
|
| + __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend).
|
| + // RAX: Tagged left (dividend).
|
| + // RCX: Tagged right (divisor).
|
| + __ cmpq(RCX, Immediate(0));
|
| + __ j(EQUAL, &fall_through);
|
| + EmitRemainderOperation(assembler);
|
| + // Untagged remainder result in RAX.
|
| + __ SmiTag(RAX);
|
| + __ ret();
|
| + __ Bind(&fall_through);
|
| + return false;
|
| +}
|
| +
|
| +
|
| bool Intrinsifier::Integer_truncDivide(Assembler* assembler) {
|
| Label fall_through, not_32bit;
|
| TestBothArgumentsSmis(assembler, &fall_through);
|
|
|