From: danno@chromium.org Date: Fri, 19 Jul 2013 08:21:41 +0000 (+0000) Subject: x64 support for d-to-i (truncated) X-Git-Tag: upstream/4.7.83~13300 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=76cbaf407fb4aca0ca3f5e65a394b25dfad5e5f6;p=platform%2Fupstream%2Fv8.git x64 support for d-to-i (truncated) R=yangguo@chromium.org Review URL: https://codereview.chromium.org/18333012 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15761 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index aee57dc..f91bde7 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -676,7 +676,7 @@ void DoubleToIStub::Generate(MacroAssembler* masm) { MemOperand mantissa_operand(MemOperand(input_reg, double_offset)); MemOperand exponent_operand(MemOperand(input_reg, - double_offset + kPointerSize)); + double_offset + kDoubleSize / 2)); Register scratch1; { diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 0b74ace..fd6ad3d 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -618,71 +618,87 @@ class FloatingPointHelper : public AllStatic { }; -// Get the integer part of a heap number. -// Overwrites the contents of rdi, rbx and rcx. Result cannot be rdi or rbx. -void IntegerConvert(MacroAssembler* masm, - Register result, - Register source) { - // Result may be rcx. If result and source are the same register, source will - // be overwritten. - ASSERT(!result.is(rdi) && !result.is(rbx)); - // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use - // cvttsd2si (32-bit version) directly. - Register double_exponent = rbx; - Register double_value = rdi; - Label done, exponent_63_plus; - // Get double and extract exponent. - __ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset)); - // Clear result preemptively, in case we need to return zero. - __ xorl(result, result); - __ movq(xmm0, double_value); // Save copy in xmm0 in case we need it there. - // Double to remove sign bit, shift exponent down to least significant bits. - // and subtract bias to get the unshifted, unbiased exponent. - __ lea(double_exponent, Operand(double_value, double_value, times_1, 0)); - __ shr(double_exponent, Immediate(64 - HeapNumber::kExponentBits)); - __ subl(double_exponent, Immediate(HeapNumber::kExponentBias)); - // Check whether the exponent is too big for a 63 bit unsigned integer. - __ cmpl(double_exponent, Immediate(63)); - __ j(above_equal, &exponent_63_plus, Label::kNear); - // Handle exponent range 0..62. - __ cvttsd2siq(result, xmm0); - __ jmp(&done, Label::kNear); +void DoubleToIStub::Generate(MacroAssembler* masm) { + Register input_reg = this->source(); + Register final_result_reg = this->destination(); + ASSERT(is_truncating()); - __ bind(&exponent_63_plus); - // Exponent negative or 63+. - __ cmpl(double_exponent, Immediate(83)); - // If exponent negative or above 83, number contains no significant bits in - // the range 0..2^31, so result is zero, and rcx already holds zero. - __ j(above, &done, Label::kNear); - - // Exponent in rage 63..83. - // Mantissa * 2^exponent contains bits in the range 2^0..2^31, namely - // the least significant exponent-52 bits. - - // Negate low bits of mantissa if value is negative. - __ addq(double_value, double_value); // Move sign bit to carry. - __ sbbl(result, result); // And convert carry to -1 in result register. - // if scratch2 is negative, do (scratch2-1)^-1, otherwise (scratch2-0)^0. - __ addl(double_value, result); - // Do xor in opposite directions depending on where we want the result - // (depending on whether result is rcx or not). - - if (result.is(rcx)) { - __ xorl(double_value, result); - // Left shift mantissa by (exponent - mantissabits - 1) to save the - // bits that have positional values below 2^32 (the extra -1 comes from the - // doubling done above to move the sign bit into the carry flag). - __ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1)); - __ shll_cl(double_value); - __ movl(result, double_value); - } else { - // As the then-branch, but move double-value to result before shifting. - __ xorl(result, double_value); - __ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1)); - __ shll_cl(result); - } + Label check_negative, process_64_bits, done; - __ bind(&done); + int double_offset = offset(); + + // Account for return address and saved regs if input is rsp. + if (input_reg.is(rsp)) double_offset += 3 * kPointerSize; + + MemOperand mantissa_operand(MemOperand(input_reg, double_offset)); + MemOperand exponent_operand(MemOperand(input_reg, + double_offset + kDoubleSize / 2)); + + Register scratch1; + Register scratch_candidates[3] = { rbx, rdx, rdi }; + for (int i = 0; i < 3; i++) { + scratch1 = scratch_candidates[i]; + if (!final_result_reg.is(scratch1) && !input_reg.is(scratch1)) break; + } + + // Since we must use rcx for shifts below, use some other register (rax) + // to calculate the result if ecx is the requested return register. + Register result_reg = final_result_reg.is(rcx) ? rax : final_result_reg; + // Save ecx if it isn't the return register and therefore volatile, or if it + // is the return register, then save the temp register we use in its stead + // for the result. + Register save_reg = final_result_reg.is(rcx) ? rax : rcx; + __ push(scratch1); + __ push(save_reg); + + bool stash_exponent_copy = !input_reg.is(rsp); + __ movl(scratch1, mantissa_operand); + __ movsd(xmm0, mantissa_operand); + __ movl(rcx, exponent_operand); + if (stash_exponent_copy) __ push(rcx); + + __ andl(rcx, Immediate(HeapNumber::kExponentMask)); + __ shrl(rcx, Immediate(HeapNumber::kExponentShift)); + __ leal(result_reg, MemOperand(rcx, -HeapNumber::kExponentBias)); + __ cmpl(result_reg, Immediate(HeapNumber::kMantissaBits)); + __ j(below, &process_64_bits); + + // Result is entirely in lower 32-bits of mantissa + int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize; + __ subl(rcx, Immediate(delta)); + __ xorl(result_reg, result_reg); + __ cmpl(rcx, Immediate(31)); + __ j(above, &done); + __ shll_cl(scratch1); + __ jmp(&check_negative); + + __ bind(&process_64_bits); + __ cvttsd2siq(result_reg, xmm0); + __ jmp(&done, Label::kNear); + + // If the double was negative, negate the integer result. + __ bind(&check_negative); + __ movl(result_reg, scratch1); + __ negl(result_reg); + if (stash_exponent_copy) { + __ cmpl(MemOperand(rsp, 0), Immediate(0)); + } else { + __ cmpl(exponent_operand, Immediate(0)); + } + __ cmovl(greater, result_reg, scratch1); + + // Restore registers + __ bind(&done); + if (stash_exponent_copy) { + __ addq(rsp, Immediate(kDoubleSize)); + } + if (!final_result_reg.is(result_reg)) { + ASSERT(final_result_reg.is(rcx)); + __ movl(final_result_reg, result_reg); + } + __ pop(save_reg); + __ pop(scratch1); + __ ret(0); } @@ -1568,12 +1584,18 @@ void FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm) { __ JumpIfSmi(rax, &rax_is_smi); __ bind(&rax_is_object); - IntegerConvert(masm, rcx, rax); // Uses rdi, rcx and rbx. + DoubleToIStub stub1(rax, rcx, HeapNumber::kValueOffset - kHeapObjectTag, + true); + __ call(stub1.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); + __ jmp(&done); __ bind(&rdx_is_object); - IntegerConvert(masm, rdx, rdx); // Uses rdi, rcx and rbx. + DoubleToIStub stub2(rdx, rdx, HeapNumber::kValueOffset - kHeapObjectTag, + true); + __ call(stub1.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); __ JumpIfNotSmi(rax, &rax_is_object); + __ bind(&rax_is_smi); __ SmiToInteger32(rcx, rax); @@ -1608,7 +1630,9 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); __ j(not_equal, &check_undefined_arg1); // Get the untagged integer version of the rdx heap number in rcx. - IntegerConvert(masm, r8, rdx); + DoubleToIStub stub1(rdx, r8, HeapNumber::kValueOffset - kHeapObjectTag, + true); + __ call(stub1.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); // Here r8 has the untagged integer, rax has a Smi or a heap number. __ bind(&load_arg2); @@ -1628,7 +1652,10 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); __ j(not_equal, &check_undefined_arg2); // Get the untagged integer version of the rax heap number in rcx. - IntegerConvert(masm, rcx, rax); + DoubleToIStub stub2(rax, rcx, HeapNumber::kValueOffset - kHeapObjectTag, + true); + __ call(stub2.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); + __ bind(&done); __ movl(rax, r8); } @@ -3347,7 +3374,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { Label first_non_object; __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); __ j(below, &first_non_object, Label::kNear); - // Return non-zero (eax (not rax) is not zero) + // Return non-zero (rax (not rax) is not zero) Label return_not_equal; STATIC_ASSERT(kHeapObjectTag != 0); __ bind(&return_not_equal); @@ -3409,7 +3436,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { masm, &check_for_strings, rdx, kScratchRegister); // We've already checked for object identity, so if both operands are - // internalized strings they aren't equal. Register eax (not rax) already + // internalized strings they aren't equal. Register rax (not rax) already // holds a non-zero value, which indicates not equal, so just return. __ ret(0); } diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index ad78606..04ca041 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -110,6 +110,7 @@ ['v8_target_arch=="ia32"', { 'sources': [ 'test-assembler-ia32.cc', + 'test-code-stubs.cc', 'test-code-stubs-ia32.cc', 'test-disasm-ia32.cc', 'test-log-stack-tracer.cc' @@ -118,6 +119,8 @@ ['v8_target_arch=="x64"', { 'sources': [ 'test-assembler-x64.cc', + 'test-code-stubs.cc', + 'test-code-stubs-x64.cc', 'test-macro-assembler-x64.cc', 'test-log-stack-tracer.cc' ], diff --git a/test/cctest/test-code-stubs-ia32.cc b/test/cctest/test-code-stubs-ia32.cc index 8e599b3..6f8de60 100644 --- a/test/cctest/test-code-stubs-ia32.cc +++ b/test/cctest/test-code-stubs-ia32.cc @@ -33,110 +33,13 @@ #include "cctest.h" #include "code-stubs.h" +#include "test-code-stubs.h" #include "factory.h" #include "macro-assembler.h" #include "platform.h" -#if __GNUC__ -#define STDCALL __attribute__((stdcall)) -#else -#define STDCALL __stdcall -#endif - using namespace v8::internal; - -typedef int32_t STDCALL ConvertDToIFuncType(double input); -typedef ConvertDToIFuncType* ConvertDToIFunc; - - -int STDCALL ConvertDToICVersion(double d) { - Address double_ptr = reinterpret_cast
(&d); - uint32_t exponent_bits = Memory::uint32_at(double_ptr + kDoubleSize / 2); - int32_t shifted_mask = static_cast(Double::kExponentMask >> 32); - int32_t exponent = (((exponent_bits & shifted_mask) >> - (Double::kPhysicalSignificandSize - 32)) - - HeapNumber::kExponentBias); - uint32_t unsigned_exponent = static_cast(exponent); - int result = 0; - uint32_t max_exponent = - static_cast(Double::kPhysicalSignificandSize); - if (unsigned_exponent >= max_exponent) { - if ((exponent - Double::kPhysicalSignificandSize) < 32) { - result = Memory::uint32_at(double_ptr) << - (exponent - Double::kPhysicalSignificandSize); - } - } else { - uint64_t big_result = - (BitCast(d) & Double::kSignificandMask) | Double::kHiddenBit; - big_result = big_result >> (Double::kPhysicalSignificandSize - exponent); - result = static_cast(big_result); - } - if (static_cast(exponent_bits) < 0) { - return (0 - result); - } else { - return result; - } -} - - -void RunOneTruncationTestWithTest(ConvertDToIFunc func, - double from, - double raw) { - uint64_t to = static_cast(raw); - int result = (*func)(from); - CHECK_EQ(static_cast(to), result); -} - - -// #define NaN and Infinity so that it's possible to cut-and-paste these tests -// directly to a .js file and run them. -#define NaN (OS::nan_value()) -#define Infinity (std::numeric_limits::infinity()) -#define RunOneTruncationTest(p1, p2) RunOneTruncationTestWithTest(func, p1, p2) - -void RunAllTruncationTests(ConvertDToIFunc func) { - RunOneTruncationTest(0, 0); - RunOneTruncationTest(0.5, 0); - RunOneTruncationTest(-0.5, 0); - RunOneTruncationTest(1.5, 1); - RunOneTruncationTest(-1.5, -1); - RunOneTruncationTest(5.5, 5); - RunOneTruncationTest(-5.0, -5); - RunOneTruncationTest(NaN, 0); - RunOneTruncationTest(Infinity, 0); - RunOneTruncationTest(-NaN, 0); - RunOneTruncationTest(-Infinity, 0); - - RunOneTruncationTest(4.5036e+15, 0x1635E000); - RunOneTruncationTest(-4.5036e+15, -372629504); - - RunOneTruncationTest(4503603922337791.0, -1); - RunOneTruncationTest(-4503603922337791.0, 1); - RunOneTruncationTest(4503601774854143.0, 2147483647); - RunOneTruncationTest(-4503601774854143.0, -2147483647); - RunOneTruncationTest(9007207844675582.0, -2); - RunOneTruncationTest(-9007207844675582.0, 2); - RunOneTruncationTest(2.4178527921507624e+24, -536870912); - RunOneTruncationTest(-2.4178527921507624e+24, 536870912); - RunOneTruncationTest(2.417853945072267e+24, -536870912); - RunOneTruncationTest(-2.417853945072267e+24, 536870912); - - RunOneTruncationTest(4.8357055843015248e+24, -1073741824); - RunOneTruncationTest(-4.8357055843015248e+24, 1073741824); - RunOneTruncationTest(4.8357078901445341e+24, -1073741824); - RunOneTruncationTest(-4.8357078901445341e+24, 1073741824); - - RunOneTruncationTest(9.6714111686030497e+24, -2147483648.0); - RunOneTruncationTest(-9.6714111686030497e+24, -2147483648.0); - RunOneTruncationTest(9.6714157802890681e+24, -2147483648.0); - RunOneTruncationTest(-9.6714157802890681e+24, -2147483648.0); -} - -#undef NaN -#undef Infinity -#undef RunOneTruncationTest - #define __ assm. ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, diff --git a/test/cctest/test-code-stubs-x64.cc b/test/cctest/test-code-stubs-x64.cc new file mode 100644 index 0000000..e30c160 --- /dev/null +++ b/test/cctest/test-code-stubs-x64.cc @@ -0,0 +1,149 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Rrdistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Rrdistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Rrdistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "v8.h" + +#include "cctest.h" +#include "code-stubs.h" +#include "test-code-stubs.h" +#include "factory.h" +#include "macro-assembler.h" +#include "platform.h" + +using namespace v8::internal; + + +#define __ assm. + +ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, + Register source_reg, + Register destination_reg) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles(isolate); + MacroAssembler assm(isolate, buffer, static_cast(actual_size)); + assm.set_allow_stub_calls(false); + int offset = + source_reg.is(rsp) ? 0 : (HeapNumber::kValueOffset - kSmiTagSize); + DoubleToIStub stub(source_reg, destination_reg, offset, true); + byte* start = stub.GetCode(isolate)->instruction_start(); + + __ push(rbx); + __ push(rcx); + __ push(rdx); + __ push(rsi); + __ push(rdi); + + if (!source_reg.is(rsp)) { + __ lea(source_reg, MemOperand(rsp, -8 * kPointerSize - offset)); + } + + int param_offset = 7 * kPointerSize; + // Save registers make sure they don't get clobbered. + int reg_num = 0; + for (;reg_num < Register::NumAllocatableRegisters(); ++reg_num) { + Register reg = Register::from_code(reg_num); + if (!reg.is(rsp) && !reg.is(rbp) && !reg.is(destination_reg)) { + __ push(reg); + param_offset += kPointerSize; + } + } + + // Re-push the double argument + __ subq(rsp, Immediate(kDoubleSize)); + __ movsd(MemOperand(rsp, 0), xmm0); + + // Call through to the actual stub + __ Call(start, RelocInfo::EXTERNAL_REFERENCE); + + __ addq(rsp, Immediate(kDoubleSize)); + + // Make sure no registers have been unexpectedly clobbered + for (--reg_num; reg_num >= 0; --reg_num) { + Register reg = Register::from_code(reg_num); + if (!reg.is(rsp) && !reg.is(rbp) && !reg.is(destination_reg)) { + __ cmpq(reg, MemOperand(rsp, 0)); + __ Assert(equal, "register was clobbered"); + __ addq(rsp, Immediate(kPointerSize)); + } + } + + __ movq(rax, destination_reg); + + __ pop(rdi); + __ pop(rsi); + __ pop(rdx); + __ pop(rcx); + __ pop(rbx); + + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + return reinterpret_cast( + reinterpret_cast(buffer)); +} + +#undef __ + + +static Isolate* GetIsolateFrom(LocalContext* context) { + return reinterpret_cast((*context)->GetIsolate()); +} + + +TEST(ConvertDToI) { + CcTest::InitializeVM(); + LocalContext context; + Isolate* isolate = GetIsolateFrom(&context); + HandleScope scope(isolate); + +#if DEBUG + // Verify that the tests actually work with the C version. In the release + // code, the compiler optimizes it away because it's all constant, but does it + // wrong, triggering an assert on gcc. + RunAllTruncationTests(&ConvertDToICVersion); +#endif + + Register source_registers[] = {rsp, rax, rbx, rcx, rdx, rsi, rdi, r8, r9}; + Register dest_registers[] = {rax, rbx, rcx, rdx, rsi, rdi, r8, r9}; + + for (size_t s = 0; s < sizeof(*source_registers); s++) { + for (size_t d = 0; d < sizeof(*dest_registers); d++) { + RunAllTruncationTests( + MakeConvertDToIFuncTrampoline(isolate, + source_registers[s], + dest_registers[d])); + } + } +} diff --git a/test/cctest/test-code-stubs.cc b/test/cctest/test-code-stubs.cc new file mode 100644 index 0000000..4050696 --- /dev/null +++ b/test/cctest/test-code-stubs.cc @@ -0,0 +1,130 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include + +#include "v8.h" + +#include "cctest.h" +#include "code-stubs.h" +#include "test-code-stubs.h" +#include "factory.h" +#include "macro-assembler.h" +#include "platform.h" + +using namespace v8::internal; + + +int STDCALL ConvertDToICVersion(double d) { + Address double_ptr = reinterpret_cast
(&d); + uint32_t exponent_bits = Memory::uint32_at(double_ptr + kDoubleSize / 2); + int32_t shifted_mask = static_cast(Double::kExponentMask >> 32); + int32_t exponent = (((exponent_bits & shifted_mask) >> + (Double::kPhysicalSignificandSize - 32)) - + HeapNumber::kExponentBias); + uint32_t unsigned_exponent = static_cast(exponent); + int result = 0; + uint32_t max_exponent = + static_cast(Double::kPhysicalSignificandSize); + if (unsigned_exponent >= max_exponent) { + if ((exponent - Double::kPhysicalSignificandSize) < 32) { + result = Memory::uint32_at(double_ptr) << + (exponent - Double::kPhysicalSignificandSize); + } + } else { + uint64_t big_result = + (BitCast(d) & Double::kSignificandMask) | Double::kHiddenBit; + big_result = big_result >> (Double::kPhysicalSignificandSize - exponent); + result = static_cast(big_result); + } + if (static_cast(exponent_bits) < 0) { + return (0 - result); + } else { + return result; + } +} + + +void RunOneTruncationTestWithTest(ConvertDToIFunc func, + double from, + double raw) { + uint64_t to = static_cast(raw); + int result = (*func)(from); + CHECK_EQ(static_cast(to), result); +} + + +// #define NaN and Infinity so that it's possible to cut-and-paste these tests +// directly to a .js file and run them. +#define NaN (OS::nan_value()) +#define Infinity (std::numeric_limits::infinity()) +#define RunOneTruncationTest(p1, p2) RunOneTruncationTestWithTest(func, p1, p2) + +void RunAllTruncationTests(ConvertDToIFunc func) { + RunOneTruncationTest(0, 0); + RunOneTruncationTest(0.5, 0); + RunOneTruncationTest(-0.5, 0); + RunOneTruncationTest(1.5, 1); + RunOneTruncationTest(-1.5, -1); + RunOneTruncationTest(5.5, 5); + RunOneTruncationTest(-5.0, -5); + RunOneTruncationTest(NaN, 0); + RunOneTruncationTest(Infinity, 0); + RunOneTruncationTest(-NaN, 0); + RunOneTruncationTest(-Infinity, 0); + + RunOneTruncationTest(4.5036e+15, 0x1635E000); + RunOneTruncationTest(-4.5036e+15, -372629504); + + RunOneTruncationTest(4503603922337791.0, -1); + RunOneTruncationTest(-4503603922337791.0, 1); + RunOneTruncationTest(4503601774854143.0, 2147483647); + RunOneTruncationTest(-4503601774854143.0, -2147483647); + RunOneTruncationTest(9007207844675582.0, -2); + RunOneTruncationTest(-9007207844675582.0, 2); + + RunOneTruncationTest(2.4178527921507624e+24, -536870912); + RunOneTruncationTest(-2.4178527921507624e+24, 536870912); + RunOneTruncationTest(2.417853945072267e+24, -536870912); + RunOneTruncationTest(-2.417853945072267e+24, 536870912); + + RunOneTruncationTest(4.8357055843015248e+24, -1073741824); + RunOneTruncationTest(-4.8357055843015248e+24, 1073741824); + RunOneTruncationTest(4.8357078901445341e+24, -1073741824); + RunOneTruncationTest(-4.8357078901445341e+24, 1073741824); + + RunOneTruncationTest(9.6714111686030497e+24, -2147483648.0); + RunOneTruncationTest(-9.6714111686030497e+24, -2147483648.0); + RunOneTruncationTest(9.6714157802890681e+24, -2147483648.0); + RunOneTruncationTest(-9.6714157802890681e+24, -2147483648.0); +} + +#undef NaN +#undef Infinity +#undef RunOneTruncationTest diff --git a/test/cctest/test-code-stubs.h b/test/cctest/test-code-stubs.h new file mode 100644 index 0000000..eab8e63 --- /dev/null +++ b/test/cctest/test-code-stubs.h @@ -0,0 +1,48 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef V8_TEST_CODE_STUBS_H_ +#define V8_TEST_CODE_STUBS_H_ + +#if V8_TARGET_ARCH_IA32 +#if __GNUC__ +#define STDCALL __attribute__((stdcall)) +#else +#define STDCALL __stdcall +#endif +#else +#define STDCALL +#endif + +typedef int32_t STDCALL ConvertDToIFuncType(double input); +typedef ConvertDToIFuncType* ConvertDToIFunc; + +int STDCALL ConvertDToICVersion(double d); + +void RunAllTruncationTests(ConvertDToIFunc func); + +#endif