From 7659beafb1d0103fda74eb573deac7e4c431fd63 Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Mon, 12 Mar 2012 14:56:04 +0000 Subject: [PATCH] Ensure consistency of Math.sqrt on Intel platforms. BUG= TEST=regress-sqrt.js Review URL: https://chromiumcodereview.appspot.com/9690010 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11012 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/codegen-arm.cc | 7 ++++-- src/codegen.h | 6 ++--- src/ia32/codegen-ia32.cc | 38 ++++++++++++++++++++++++++--- src/mips/codegen-mips.cc | 7 ++++-- src/platform-posix.cc | 42 ++++++++++++++++---------------- src/platform-win32.cc | 42 ++++++++++++++++---------------- src/platform.h | 1 + src/runtime.cc | 8 +++--- src/x64/codegen-x64.cc | 29 +++++++++++++++++++--- test/mjsunit/regress/regress-sqrt.js | 47 ++++++++++++++++++++++++++++++++++++ 10 files changed, 169 insertions(+), 58 deletions(-) create mode 100644 test/mjsunit/regress/regress-sqrt.js diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index 6e18277..befd8f2 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -37,8 +37,7 @@ namespace internal { #define __ ACCESS_MASM(masm) -TranscendentalFunction CreateTranscendentalFunction( - TranscendentalCache::Type type) { +UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { switch (type) { case TranscendentalCache::SIN: return &sin; case TranscendentalCache::COS: return &cos; @@ -50,6 +49,10 @@ TranscendentalFunction CreateTranscendentalFunction( } +UnaryMathFunction CreateSqrtFunction() { + return &sqrt; +} + // ------------------------------------------------------------------------- // Platform-specific RuntimeCallHelper functions. diff --git a/src/codegen.h b/src/codegen.h index 28a3006..50d70f2 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -87,10 +87,10 @@ namespace internal { // Results of the library implementation of transcendental functions may differ // from the one we use in our generated code. Therefore we use the same // generated code both in runtime and compiled code. -typedef double (*TranscendentalFunction)(double x); +typedef double (*UnaryMathFunction)(double x); -TranscendentalFunction CreateTranscendentalFunction( - TranscendentalCache::Type type); +UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type); +UnaryMathFunction CreateSqrtFunction(); class ElementsTransitionGenerator : public AllStatic { diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index de6901f..ea61910 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -57,8 +57,7 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { #define __ masm. -TranscendentalFunction CreateTranscendentalFunction( - TranscendentalCache::Type type) { +UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { size_t actual_size; // Allocate buffer in executable space. byte* buffer = static_cast(OS::Allocate(1 * KB, @@ -99,7 +98,40 @@ TranscendentalFunction CreateTranscendentalFunction( CPU::FlushICache(buffer, actual_size); OS::ProtectCode(buffer, actual_size); - return FUNCTION_CAST(buffer); + return FUNCTION_CAST(buffer); +} + + +UnaryMathFunction CreateSqrtFunction() { + size_t actual_size; + // Allocate buffer in executable space. + byte* buffer = static_cast(OS::Allocate(1 * KB, + &actual_size, + true)); + // If SSE2 is not available, we can use libc's implementation to ensure + // consistency since code by fullcodegen's calls into runtime in that case. + if (buffer == NULL || !CpuFeatures::IsSupported(SSE2)) return &sqrt; + MacroAssembler masm(NULL, buffer, static_cast(actual_size)); + // esp[1 * kPointerSize]: raw double input + // esp[0 * kPointerSize]: return address + // Move double input into registers. + { + CpuFeatures::Scope use_sse2(SSE2); + __ movdbl(xmm0, Operand(esp, 1 * kPointerSize)); + __ sqrtsd(xmm0, xmm0); + __ movdbl(Operand(esp, 1 * kPointerSize), xmm0); + // Load result into floating point register as return value. + __ fld_d(Operand(esp, 1 * kPointerSize)); + __ Ret(); + } + + CodeDesc desc; + masm.GetCode(&desc); + ASSERT(desc.reloc_size == 0); + + CPU::FlushICache(buffer, actual_size); + OS::ProtectCode(buffer, actual_size); + return FUNCTION_CAST(buffer); } diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc index 8cbb771..9acccdc 100644 --- a/src/mips/codegen-mips.cc +++ b/src/mips/codegen-mips.cc @@ -37,8 +37,7 @@ namespace internal { #define __ ACCESS_MASM(masm) -TranscendentalFunction CreateTranscendentalFunction( - TranscendentalCache::Type type) { +UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { switch (type) { case TranscendentalCache::SIN: return &sin; case TranscendentalCache::COS: return &cos; @@ -50,6 +49,10 @@ TranscendentalFunction CreateTranscendentalFunction( } +UnaryMathFunction CreateSqrtFunction() { + return &sqrt; +} + // ------------------------------------------------------------------------- // Platform-specific RuntimeCallHelper functions. diff --git a/src/platform-posix.cc b/src/platform-posix.cc index 51fa1ec..4221808 100644 --- a/src/platform-posix.cc +++ b/src/platform-posix.cc @@ -127,27 +127,27 @@ double modulo(double x, double y) { } -static Mutex* transcendental_function_mutex = OS::CreateMutex(); - -#define TRANSCENDENTAL_FUNCTION(name, type) \ -static TranscendentalFunction fast_##name##_function = NULL; \ -double fast_##name(double x) { \ - if (fast_##name##_function == NULL) { \ - ScopedLock lock(transcendental_function_mutex); \ - TranscendentalFunction temp = \ - CreateTranscendentalFunction(type); \ - MemoryBarrier(); \ - fast_##name##_function = temp; \ - } \ - return (*fast_##name##_function)(x); \ -} - -TRANSCENDENTAL_FUNCTION(sin, TranscendentalCache::SIN) -TRANSCENDENTAL_FUNCTION(cos, TranscendentalCache::COS) -TRANSCENDENTAL_FUNCTION(tan, TranscendentalCache::TAN) -TRANSCENDENTAL_FUNCTION(log, TranscendentalCache::LOG) - -#undef TRANSCENDENTAL_FUNCTION +static Mutex* math_function_mutex = OS::CreateMutex(); + +#define UNARY_MATH_FUNCTION(name, generator) \ +static UnaryMathFunction fast_##name##_function = NULL; \ +double fast_##name(double x) { \ + if (fast_##name##_function == NULL) { \ + ScopedLock lock(math_function_mutex); \ + UnaryMathFunction temp = generator; \ + MemoryBarrier(); \ + fast_##name##_function = temp; \ + } \ + return (*fast_##name##_function)(x); \ +} + +UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) +UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) +UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) +UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) +UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) + +#undef MATH_FUNCTION double OS::nan_value() { diff --git a/src/platform-win32.cc b/src/platform-win32.cc index 98f04ea..2a25f04 100644 --- a/src/platform-win32.cc +++ b/src/platform-win32.cc @@ -208,27 +208,27 @@ double modulo(double x, double y) { #endif // _WIN64 -static Mutex* transcendental_function_mutex = OS::CreateMutex(); - -#define TRANSCENDENTAL_FUNCTION(name, type) \ -static TranscendentalFunction fast_##name##_function = NULL; \ -double fast_##name(double x) { \ - if (fast_##name##_function == NULL) { \ - ScopedLock lock(transcendental_function_mutex); \ - TranscendentalFunction temp = \ - CreateTranscendentalFunction(type); \ - MemoryBarrier(); \ - fast_##name##_function = temp; \ - } \ - return (*fast_##name##_function)(x); \ -} - -TRANSCENDENTAL_FUNCTION(sin, TranscendentalCache::SIN) -TRANSCENDENTAL_FUNCTION(cos, TranscendentalCache::COS) -TRANSCENDENTAL_FUNCTION(tan, TranscendentalCache::TAN) -TRANSCENDENTAL_FUNCTION(log, TranscendentalCache::LOG) - -#undef TRANSCENDENTAL_FUNCTION +static Mutex* math_function_mutex = OS::CreateMutex(); + +#define UNARY_MATH_FUNCTION(name, generator) \ +static UnaryMathFunction fast_##name##_function = NULL; \ +double fast_##name(double x) { \ + if (fast_##name##_function == NULL) { \ + ScopedLock lock(math_function_mutex); \ + UnaryMathFunction temp = generator; \ + MemoryBarrier(); \ + fast_##name##_function = temp; \ + } \ + return (*fast_##name##_function)(x); \ +} + +UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) +UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) +UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) +UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) +UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) + +#undef MATH_FUNCTION // ---------------------------------------------------------------------------- diff --git a/src/platform.h b/src/platform.h index db09806..4ec6057 100644 --- a/src/platform.h +++ b/src/platform.h @@ -102,6 +102,7 @@ double fast_sin(double input); double fast_cos(double input); double fast_tan(double input); double fast_log(double input); +double fast_sqrt(double input); // Forward declarations. class Socket; diff --git a/src/runtime.cc b/src/runtime.cc index 2a8e54f..f9e882e 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -7441,9 +7441,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { if (y == y_int) { result = power_double_int(x, y_int); // Returns 1 if exponent is 0. } else if (y == 0.5) { - result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0. + result = (isinf(x)) ? V8_INFINITY + : fast_sqrt(x + 0.0); // Convert -0 to +0. } else if (y == -0.5) { - result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0. + result = (isinf(x)) ? 0 + : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0. } else { result = power_double_double(x, y); } @@ -7529,7 +7531,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) { isolate->counters()->math_sqrt()->Increment(); CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->heap()->AllocateHeapNumber(sqrt(x)); + return isolate->heap()->AllocateHeapNumber(fast_sqrt(x)); } diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 902f7e9..a8d39b2 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -55,8 +55,7 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { #define __ masm. -TranscendentalFunction CreateTranscendentalFunction( - TranscendentalCache::Type type) { +UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { size_t actual_size; // Allocate buffer in executable space. byte* buffer = static_cast(OS::Allocate(1 * KB, @@ -96,7 +95,31 @@ TranscendentalFunction CreateTranscendentalFunction( CPU::FlushICache(buffer, actual_size); OS::ProtectCode(buffer, actual_size); - return FUNCTION_CAST(buffer); + return FUNCTION_CAST(buffer); +} + + +UnaryMathFunction CreateSqrtFunction() { + size_t actual_size; + // Allocate buffer in executable space. + byte* buffer = static_cast(OS::Allocate(1 * KB, + &actual_size, + true)); + if (buffer == NULL) return &sqrt; + + MacroAssembler masm(NULL, buffer, static_cast(actual_size)); + // xmm0: raw double input. + // Move double input into registers. + __ sqrtsd(xmm0, xmm0); + __ Ret(); + + CodeDesc desc; + masm.GetCode(&desc); + ASSERT(desc.reloc_size == 0); + + CPU::FlushICache(buffer, actual_size); + OS::ProtectCode(buffer, actual_size); + return FUNCTION_CAST(buffer); } diff --git a/test/mjsunit/regress/regress-sqrt.js b/test/mjsunit/regress/regress-sqrt.js new file mode 100644 index 0000000..f2a7e55 --- /dev/null +++ b/test/mjsunit/regress/regress-sqrt.js @@ -0,0 +1,47 @@ +// Copyright 2012 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. + +// Flags: --allow-natives-syntax + +// Check that Math.sqrt returns the same value regardless of being +// optimized or not. + +function f(x) { + return Math.sqrt(x); +} + +var x = 7.0506280066499245e-233; + +var a = f(x); + +f(0.1); +f(0.2); +%OptimizeFunctionOnNextCall(f); + +var b = f(x); + +assertEquals(a, b); -- 2.7.4