| Index: bleeding_edge/src/ia32/codegen-ia32.cc
|
| ===================================================================
|
| --- bleeding_edge/src/ia32/codegen-ia32.cc (revision 3511)
|
| +++ bleeding_edge/src/ia32/codegen-ia32.cc (working copy)
|
| @@ -5515,12 +5515,12 @@
|
|
|
| } else {
|
| Load(node->expression());
|
| + bool overwrite =
|
| + (node->expression()->AsBinaryOperation() != NULL &&
|
| + node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
|
| switch (op) {
|
| case Token::SUB: {
|
| - bool overwrite =
|
| - (node->expression()->AsBinaryOperation() != NULL &&
|
| - node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
|
| - UnarySubStub stub(overwrite);
|
| + GenericUnaryOpStub stub(Token::SUB, overwrite);
|
| // TODO(1222589): remove dependency of TOS being cached inside stub
|
| Result operand = frame_->Pop();
|
| Result answer = frame_->CallStub(&stub, &operand);
|
| @@ -5537,16 +5537,16 @@
|
| __ test(operand.reg(), Immediate(kSmiTagMask));
|
| smi_label.Branch(zero, &operand, taken);
|
|
|
| - frame_->Push(&operand); // undo popping of TOS
|
| - Result answer = frame_->InvokeBuiltin(Builtins::BIT_NOT,
|
| - CALL_FUNCTION, 1);
|
| + GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
|
| + Result answer = frame_->CallStub(&stub, &operand);
|
| + continue_label.Jump(&answer);
|
|
|
| - continue_label.Jump(&answer);
|
| smi_label.Bind(&answer);
|
| answer.ToRegister();
|
| frame_->Spill(answer.reg());
|
| __ not_(answer.reg());
|
| __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag.
|
| +
|
| continue_label.Bind(&answer);
|
| frame_->Push(&answer);
|
| break;
|
| @@ -7282,9 +7282,15 @@
|
| default: UNREACHABLE();
|
| }
|
| // Store the result in the HeapNumber and return.
|
| - __ mov(Operand(esp, 1 * kPointerSize), ebx);
|
| - __ fild_s(Operand(esp, 1 * kPointerSize));
|
| - __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
|
| + if (CpuFeatures::IsSupported(SSE2)) {
|
| + CpuFeatures::Scope use_sse2(SSE2);
|
| + __ cvtsi2sd(xmm0, Operand(ebx));
|
| + __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
|
| + } else {
|
| + __ mov(Operand(esp, 1 * kPointerSize), ebx);
|
| + __ fild_s(Operand(esp, 1 * kPointerSize));
|
| + __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
|
| + }
|
| GenerateReturn(masm);
|
| }
|
|
|
| @@ -7696,67 +7702,119 @@
|
| }
|
|
|
|
|
| -void UnarySubStub::Generate(MacroAssembler* masm) {
|
| - Label undo;
|
| - Label slow;
|
| - Label done;
|
| - Label try_float;
|
| +void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
|
| + Label slow, done;
|
|
|
| - // Check whether the value is a smi.
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(not_zero, &try_float, not_taken);
|
| + if (op_ == Token::SUB) {
|
| + // Check whether the value is a smi.
|
| + Label try_float;
|
| + __ test(eax, Immediate(kSmiTagMask));
|
| + __ j(not_zero, &try_float, not_taken);
|
|
|
| - // Enter runtime system if the value of the expression is zero
|
| - // to make sure that we switch between 0 and -0.
|
| - __ test(eax, Operand(eax));
|
| - __ j(zero, &slow, not_taken);
|
| + // Go slow case if the value of the expression is zero
|
| + // to make sure that we switch between 0 and -0.
|
| + __ test(eax, Operand(eax));
|
| + __ j(zero, &slow, not_taken);
|
|
|
| - // The value of the expression is a smi that is not zero. Try
|
| - // optimistic subtraction '0 - value'.
|
| - __ mov(edx, Operand(eax));
|
| - __ Set(eax, Immediate(0));
|
| - __ sub(eax, Operand(edx));
|
| - __ j(overflow, &undo, not_taken);
|
| + // The value of the expression is a smi that is not zero. Try
|
| + // optimistic subtraction '0 - value'.
|
| + Label undo;
|
| + __ mov(edx, Operand(eax));
|
| + __ Set(eax, Immediate(0));
|
| + __ sub(eax, Operand(edx));
|
| + __ j(overflow, &undo, not_taken);
|
|
|
| - // If result is a smi we are done.
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, &done, taken);
|
| + // If result is a smi we are done.
|
| + __ test(eax, Immediate(kSmiTagMask));
|
| + __ j(zero, &done, taken);
|
|
|
| - // Restore eax and enter runtime system.
|
| - __ bind(&undo);
|
| - __ mov(eax, Operand(edx));
|
| + // Restore eax and go slow case.
|
| + __ bind(&undo);
|
| + __ mov(eax, Operand(edx));
|
| + __ jmp(&slow);
|
|
|
| - // Enter runtime system.
|
| - __ bind(&slow);
|
| - __ pop(ecx); // pop return address
|
| - __ push(eax);
|
| - __ push(ecx); // push return address
|
| - __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
|
| + // Try floating point case.
|
| + __ bind(&try_float);
|
| + __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
|
| + __ cmp(edx, Factory::heap_number_map());
|
| + __ j(not_equal, &slow);
|
| + if (overwrite_) {
|
| + __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
|
| + __ xor_(edx, HeapNumber::kSignMask); // Flip sign.
|
| + __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), edx);
|
| + } else {
|
| + __ mov(edx, Operand(eax));
|
| + // edx: operand
|
| + __ AllocateHeapNumber(eax, ebx, ecx, &undo);
|
| + // eax: allocated 'empty' number
|
| + __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
|
| + __ xor_(ecx, HeapNumber::kSignMask); // Flip sign.
|
| + __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx);
|
| + __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset));
|
| + __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
|
| + }
|
| + } else if (op_ == Token::BIT_NOT) {
|
| + // Check if the operand is a heap number.
|
| + __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
|
| + __ cmp(edx, Factory::heap_number_map());
|
| + __ j(not_equal, &slow, not_taken);
|
|
|
| - // Try floating point case.
|
| - __ bind(&try_float);
|
| - __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
|
| - __ cmp(edx, Factory::heap_number_map());
|
| - __ j(not_equal, &slow);
|
| - if (overwrite_) {
|
| - __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
|
| - __ xor_(edx, HeapNumber::kSignMask); // Flip sign.
|
| - __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), edx);
|
| + // Convert the heap number in eax to an untagged integer in ecx.
|
| + IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), &slow);
|
| +
|
| + // Do the bitwise operation and check if the result fits in a smi.
|
| + Label try_float;
|
| + __ not_(ecx);
|
| + __ cmp(ecx, 0xc0000000);
|
| + __ j(sign, &try_float, not_taken);
|
| +
|
| + // Tag the result as a smi and we're done.
|
| + ASSERT(kSmiTagSize == 1);
|
| + __ lea(eax, Operand(ecx, times_2, kSmiTag));
|
| + __ jmp(&done);
|
| +
|
| + // Try to store the result in a heap number.
|
| + __ bind(&try_float);
|
| + if (!overwrite_) {
|
| + // Allocate a fresh heap number, but don't overwrite eax until
|
| + // we're sure we can do it without going through the slow case
|
| + // that needs the value in eax.
|
| + __ AllocateHeapNumber(ebx, edx, edi, &slow);
|
| + __ mov(eax, Operand(ebx));
|
| + }
|
| + if (CpuFeatures::IsSupported(SSE2)) {
|
| + CpuFeatures::Scope use_sse2(SSE2);
|
| + __ cvtsi2sd(xmm0, Operand(ecx));
|
| + __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
|
| + } else {
|
| + __ push(ecx);
|
| + __ fild_s(Operand(esp, 0));
|
| + __ pop(ecx);
|
| + __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
|
| + }
|
| } else {
|
| - __ mov(edx, Operand(eax));
|
| - // edx: operand
|
| - __ AllocateHeapNumber(eax, ebx, ecx, &undo);
|
| - // eax: allocated 'empty' number
|
| - __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
|
| - __ xor_(ecx, HeapNumber::kSignMask); // Flip sign.
|
| - __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx);
|
| - __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset));
|
| - __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
|
| + UNIMPLEMENTED();
|
| }
|
|
|
| + // Return from the stub.
|
| __ bind(&done);
|
| + __ StubReturn(1);
|
|
|
| - __ StubReturn(1);
|
| + // Handle the slow case by jumping to the JavaScript builtin.
|
| + __ bind(&slow);
|
| + __ pop(ecx); // pop return address.
|
| + __ push(eax);
|
| + __ push(ecx); // push return address
|
| + switch (op_) {
|
| + case Token::SUB:
|
| + __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
|
| + break;
|
| + case Token::BIT_NOT:
|
| + __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| }
|
|
|
|
|
|
|