From: erik.corry@gmail.com Date: Wed, 17 Nov 2010 09:24:44 +0000 (+0000) Subject: Implement Math.floor stub on ARM. Uses VFP when available. This is a commit of http... X-Git-Tag: upstream/4.7.83~20950 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f42de7dcae428e39d2aa9e89c3f7955e4a41805b;p=platform%2Fupstream%2Fv8.git Implement Math.floor stub on ARM. Uses VFP when available. This is a commit of codereview.chromium.org/5075002/ for Martyn Capewell git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5835 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index de3931c..606ff86 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -219,6 +219,11 @@ const DwVfpRegister d13 = { 13 }; const DwVfpRegister d14 = { 14 }; const DwVfpRegister d15 = { 15 }; +// VFP FPSCR constants. +static const uint32_t kVFPExceptionMask = 0xf; +static const uint32_t kVFPRoundingModeMask = 3 << 22; +static const uint32_t kVFPFlushToZeroMask = 1 << 24; +static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22; // Coprocessor register struct CRegister { diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 5e29c2e..a0ef80a 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -1676,8 +1676,143 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object, JSGlobalPropertyCell* cell, JSFunction* function, String* name) { - // TODO(872): implement this. - return Heap::undefined_value(); + // ----------- S t a t e ------------- + // -- r2 : function name + // -- lr : return address + // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) + // -- ... + // -- sp[argc * 4] : receiver + // ----------------------------------- + + if (!CpuFeatures::IsSupported(VFP3)) return Heap::undefined_value(); + CpuFeatures::Scope scope_vfp3(VFP3); + + const int argc = arguments().immediate(); + + // If the object is not a JSObject or we got an unexpected number of + // arguments, bail out to the regular call. + if (!object->IsJSObject() || argc != 1) return Heap::undefined_value(); + + Label miss, slow; + GenerateNameCheck(name, &miss); + + if (cell == NULL) { + __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); + + STATIC_ASSERT(kSmiTag == 0); + __ BranchOnSmi(r1, &miss); + + CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name, + &miss); + } else { + ASSERT(cell->value() == function); + GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); + GenerateLoadFunctionFromCell(cell, function, &miss); + } + + // Load the (only) argument into r0. + __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); + + // If the argument is a smi, just return. + STATIC_ASSERT(kSmiTag == 0); + __ tst(r0, Operand(kSmiTagMask)); + __ Drop(argc + 1, eq); + __ Ret(eq); + + __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, true); + + Label wont_fit_smi, no_vfp_exception, restore_fpscr_and_return; + + // If vfp3 is enabled, we use the fpu rounding with the RM (round towards + // minus infinity) mode. + + // Load the HeapNumber value. + // We will need access to the value in the core registers, so we load it + // with ldrd and move it to the fpu. It also spares a sub instruction for + // updating the HeapNumber value address, as vldr expects a multiple + // of 4 offset. + __ Ldrd(r4, r5, FieldMemOperand(r0, HeapNumber::kValueOffset)); + __ vmov(d1, r4, r5); + + // Backup FPSCR. + __ vmrs(r3); + // Set custom FPCSR: + // - Set rounding mode to "Round towards Minus Infinity" + // (ie bits [23:22] = 0b10). + // - Clear vfp cumulative exception flags (bits [3:0]). + // - Make sure Flush-to-zero mode control bit is unset (bit 22). + __ bic(r9, r3, + Operand(kVFPExceptionMask | kVFPRoundingModeMask | kVFPFlushToZeroMask)); + __ orr(r9, r9, Operand(kVFPRoundToMinusInfinityBits)); + __ vmsr(r9); + + // Convert the argument to an integer. + __ vcvt_s32_f64(s0, d1, Assembler::FPSCRRounding, al); + + // Use vcvt latency to start checking for special cases. + // Get the argument exponent and clear the sign bit. + __ bic(r6, r5, Operand(HeapNumber::kSignMask)); + __ mov(r6, Operand(r6, LSR, HeapNumber::kMantissaBitsInTopWord)); + + // Retrieve FPSCR and check for vfp exceptions. + __ vmrs(r9); + __ tst(r9, Operand(kVFPExceptionMask)); + __ b(&no_vfp_exception, eq); + + // Check for NaN, Infinity, and -Infinity. + // They are invariant through a Math.Floor call, so just + // return the original argument. + __ sub(r7, r6, Operand(HeapNumber::kExponentMask + >> HeapNumber::kMantissaBitsInTopWord), SetCC); + __ b(&restore_fpscr_and_return, eq); + // We had an overflow or underflow in the conversion. Check if we + // have a big exponent. + __ cmp(r7, Operand(HeapNumber::kMantissaBits)); + // If greater or equal, the argument is already round and in r0. + __ b(&restore_fpscr_and_return, ge); + __ b(&slow); + + __ bind(&no_vfp_exception); + // Move the result back to general purpose register r0. + __ vmov(r0, s0); + // Check if the result fits into a smi. + __ add(r1, r0, Operand(0x40000000), SetCC); + __ b(&wont_fit_smi, mi); + // Tag the result. + STATIC_ASSERT(kSmiTag == 0); + __ mov(r0, Operand(r0, LSL, kSmiTagSize)); + + // Check for -0. + __ cmp(r0, Operand(0)); + __ b(&restore_fpscr_and_return, ne); + // r5 already holds the HeapNumber exponent. + __ tst(r5, Operand(HeapNumber::kSignMask)); + // If our HeapNumber is negative it was -0, so load its address and return. + // Else r0 is loaded with 0, so we can also just return. + __ ldr(r0, MemOperand(sp, 0 * kPointerSize), ne); + + __ bind(&restore_fpscr_and_return); + // Restore FPSCR and return. + __ vmsr(r3); + __ Drop(argc + 1); + __ Ret(); + + __ bind(&wont_fit_smi); + __ bind(&slow); + // Restore FPCSR and fall to slow case. + __ vmsr(r3); + + // Tail call the full function. We do not have to patch the receiver + // because the function makes no use of it. + __ InvokeFunction(function, arguments(), JUMP_FUNCTION); + + __ bind(&miss); + // r2: function name. + MaybeObject* obj = GenerateMissBranch(); + if (obj->IsFailure()) return obj; + + // Return the generated code. + return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); }