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; |
} |