| Index: runtime/vm/intrinsifier_ia32.cc
|
| ===================================================================
|
| --- runtime/vm/intrinsifier_ia32.cc (revision 21658)
|
| +++ runtime/vm/intrinsifier_ia32.cc (working copy)
|
| @@ -667,35 +667,107 @@
|
| }
|
|
|
|
|
| +// Optimizations:
|
| +// - result is 0 if:
|
| +// - left is 0
|
| +// - left equals right
|
| +// - result is left if
|
| +// - left > 0 && left < right
|
| +// EAX: Tagged left (dividend).
|
| +// EBX: Tagged right (divisor).
|
| +// EDX: Untagged result (remainder).
|
| +void EmitRemainderOperation(Assembler* assembler) {
|
| + Label return_zero, modulo;
|
| + // Check for quick zero results.
|
| + __ cmpl(EAX, Immediate(0));
|
| + __ j(EQUAL, &return_zero, Assembler::kNearJump);
|
| + __ cmpl(EAX, EBX);
|
| + __ j(EQUAL, &return_zero, Assembler::kNearJump);
|
| +
|
| + // Check if result equals left.
|
| + __ cmpl(EAX, Immediate(0));
|
| + __ j(LESS, &modulo, Assembler::kNearJump);
|
| + // left is positive.
|
| + __ cmpl(EAX, EBX);
|
| + __ j(GREATER, &modulo, Assembler::kNearJump);
|
| + // left is less than right, result is left (EAX).
|
| + __ ret();
|
| +
|
| + __ Bind(&return_zero);
|
| + __ xorl(EAX, EAX);
|
| + __ ret();
|
| +
|
| + __ Bind(&modulo);
|
| + __ SmiUntag(EBX);
|
| + __ SmiUntag(EAX);
|
| + __ cdq();
|
| + __ idivl(EBX);
|
| +}
|
| +
|
| +
|
| +// 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, return_zero, try_modulo;
|
| + Label fall_through, subtract;
|
| TestBothArgumentsSmis(assembler, &fall_through);
|
| // EAX: right argument (divisor)
|
| + __ movl(EBX, EAX);
|
| + __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend).
|
| + // EAX: Tagged left (dividend).
|
| + // EBX: Tagged right (divisor).
|
| // Check if modulo by zero -> exception thrown in main function.
|
| + __ cmpl(EBX, Immediate(0));
|
| + __ j(EQUAL, &fall_through, Assembler::kNearJump);
|
| + EmitRemainderOperation(assembler);
|
| + // Untagged remainder result in EDX.
|
| + Label done;
|
| + __ movl(EAX, EDX);
|
| __ cmpl(EAX, Immediate(0));
|
| - __ j(EQUAL, &fall_through, Assembler::kNearJump);
|
| - __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend).
|
| + __ j(GREATER_EQUAL, &done, Assembler::kNearJump);
|
| + // Result is negative, adjust it.
|
| __ cmpl(EBX, Immediate(0));
|
| - __ j(LESS, &fall_through, Assembler::kNearJump);
|
| - __ cmpl(EBX, EAX);
|
| - __ j(EQUAL, &return_zero, Assembler::kNearJump);
|
| - __ j(GREATER, &try_modulo, Assembler::kNearJump);
|
| - __ movl(EAX, EBX); // Return dividend as it is smaller than divisor.
|
| + __ j(LESS, &subtract, Assembler::kNearJump);
|
| + __ addl(EAX, EBX);
|
| + __ SmiTag(EAX);
|
| __ ret();
|
| - __ Bind(&return_zero);
|
| - __ xorl(EAX, EAX); // Return zero.
|
| +
|
| + __ Bind(&subtract);
|
| + __ subl(EAX, EBX);
|
| +
|
| + __ Bind(&done);
|
| + // The remainder of two Smi-s is always a Smi, no overflow check needed.
|
| + __ SmiTag(EAX);
|
| __ ret();
|
| - __ Bind(&try_modulo);
|
| - // EAX: right (non-null divisor).
|
| +
|
| + __ Bind(&fall_through);
|
| + return false;
|
| +}
|
| +
|
| +
|
| +bool Intrinsifier::Integer_remainder(Assembler* assembler) {
|
| + Label fall_through;
|
| + TestBothArgumentsSmis(assembler, &fall_through);
|
| + // EAX: right argument (divisor)
|
| __ movl(EBX, EAX);
|
| - __ SmiUntag(EBX);
|
| __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend).
|
| - __ SmiUntag(EAX);
|
| - __ cdq();
|
| - __ idivl(EBX);
|
| + // EAX: Tagged left (dividend).
|
| + // EBX: Tagged right (divisor).
|
| + // Check if modulo by zero -> exception thrown in main function.
|
| + __ cmpl(EBX, Immediate(0));
|
| + __ j(EQUAL, &fall_through, Assembler::kNearJump);
|
| + EmitRemainderOperation(assembler);
|
| + // Untagged remainder result in EDX.
|
| __ movl(EAX, EDX);
|
| __ SmiTag(EAX);
|
| __ ret();
|
| +
|
| __ Bind(&fall_through);
|
| return false;
|
| }
|
|
|