From 28417584d8e98ae7eac22e92b952778f8ea94047 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 5 Nov 2018 15:37:36 -0800 Subject: [PATCH] Adding some new functions to System.Math and System.MathF (#20788) * Adding BitIncrement, BitDecrement, CopySign, MaxMagnitude, and MinMagnitude to Math and MathF * Adding FusedMultiplyAdd, IlogB, Log2, and ScaleB to Math and MathF * Adding some basic PAL tests for fma, ilogb, log2, and scalbn * Fixing a couple typos and adding clarifying comments * Fixing the MSVC _VVV FCALL declarations --- src/System.Private.CoreLib/shared/System/Math.cs | 99 +++++++++++--- src/System.Private.CoreLib/shared/System/MathF.cs | 97 ++++++++++--- .../src/System/Math.CoreCLR.cs | 12 ++ .../src/System/MathF.CoreCLR.cs | 12 ++ src/classlibnative/float/floatdouble.cpp | 36 +++++ src/classlibnative/float/floatsingle.cpp | 36 +++++ src/classlibnative/inc/floatdouble.h | 4 + src/classlibnative/inc/floatsingle.h | 4 + src/jit/importer.cpp | 12 +- src/jit/lsraxarch.cpp | 4 +- src/pal/inc/pal.h | 18 ++- src/pal/src/cruntime/math.cpp | 152 +++++++++++++++++++++ src/pal/src/include/pal/palinternal.h | 8 ++ .../tests/palsuite/c_runtime/fma/CMakeLists.txt | 3 + .../palsuite/c_runtime/fma/test1/CMakeLists.txt | 17 +++ .../tests/palsuite/c_runtime/fma/test1/test1.cpp | 151 ++++++++++++++++++++ .../palsuite/c_runtime/fma/test1/testinfo.dat | 17 +++ .../tests/palsuite/c_runtime/fmaf/CMakeLists.txt | 3 + .../palsuite/c_runtime/fmaf/test1/CMakeLists.txt | 17 +++ .../tests/palsuite/c_runtime/fmaf/test1/test1.c | 150 ++++++++++++++++++++ .../palsuite/c_runtime/fmaf/test1/testinfo.dat | 17 +++ .../tests/palsuite/c_runtime/ilogb/CMakeLists.txt | 3 + .../palsuite/c_runtime/ilogb/test1/CMakeLists.txt | 17 +++ .../tests/palsuite/c_runtime/ilogb/test1/test1.cpp | 101 ++++++++++++++ .../palsuite/c_runtime/ilogb/test1/testinfo.dat | 17 +++ .../tests/palsuite/c_runtime/ilogbf/CMakeLists.txt | 3 + .../palsuite/c_runtime/ilogbf/test1/CMakeLists.txt | 17 +++ .../tests/palsuite/c_runtime/ilogbf/test1/test1.c | 101 ++++++++++++++ .../palsuite/c_runtime/ilogbf/test1/testinfo.dat | 17 +++ .../tests/palsuite/c_runtime/log2/CMakeLists.txt | 3 + .../palsuite/c_runtime/log2/test1/CMakeLists.txt | 17 +++ .../tests/palsuite/c_runtime/log2/test1/test1.cpp | 139 +++++++++++++++++++ .../palsuite/c_runtime/log2/test1/testinfo.dat | 17 +++ .../tests/palsuite/c_runtime/log2f/CMakeLists.txt | 3 + .../palsuite/c_runtime/log2f/test1/CMakeLists.txt | 17 +++ .../tests/palsuite/c_runtime/log2f/test1/test1.c | 138 +++++++++++++++++++ .../palsuite/c_runtime/log2f/test1/testinfo.dat | 17 +++ .../tests/palsuite/c_runtime/scalbn/CMakeLists.txt | 3 + .../palsuite/c_runtime/scalbn/test1/CMakeLists.txt | 17 +++ .../palsuite/c_runtime/scalbn/test1/test1.cpp | 140 +++++++++++++++++++ .../palsuite/c_runtime/scalbn/test1/testinfo.dat | 17 +++ .../palsuite/c_runtime/scalbnf/CMakeLists.txt | 3 + .../c_runtime/scalbnf/test1/CMakeLists.txt | 17 +++ .../tests/palsuite/c_runtime/scalbnf/test1/test1.c | 139 +++++++++++++++++++ .../palsuite/c_runtime/scalbnf/test1/testinfo.dat | 17 +++ src/vm/ecalllist.h | 8 ++ src/vm/fcall.h | 7 + 47 files changed, 1814 insertions(+), 50 deletions(-) create mode 100644 src/pal/tests/palsuite/c_runtime/fma/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/fma/test1/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/fma/test1/test1.cpp create mode 100644 src/pal/tests/palsuite/c_runtime/fma/test1/testinfo.dat create mode 100644 src/pal/tests/palsuite/c_runtime/fmaf/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/fmaf/test1/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/fmaf/test1/test1.c create mode 100644 src/pal/tests/palsuite/c_runtime/fmaf/test1/testinfo.dat create mode 100644 src/pal/tests/palsuite/c_runtime/ilogb/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/ilogb/test1/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/ilogb/test1/test1.cpp create mode 100644 src/pal/tests/palsuite/c_runtime/ilogb/test1/testinfo.dat create mode 100644 src/pal/tests/palsuite/c_runtime/ilogbf/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/ilogbf/test1/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/ilogbf/test1/test1.c create mode 100644 src/pal/tests/palsuite/c_runtime/ilogbf/test1/testinfo.dat create mode 100644 src/pal/tests/palsuite/c_runtime/log2/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/log2/test1/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/log2/test1/test1.cpp create mode 100644 src/pal/tests/palsuite/c_runtime/log2/test1/testinfo.dat create mode 100644 src/pal/tests/palsuite/c_runtime/log2f/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/log2f/test1/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/log2f/test1/test1.c create mode 100644 src/pal/tests/palsuite/c_runtime/log2f/test1/testinfo.dat create mode 100644 src/pal/tests/palsuite/c_runtime/scalbn/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/scalbn/test1/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/scalbn/test1/test1.cpp create mode 100644 src/pal/tests/palsuite/c_runtime/scalbn/test1/testinfo.dat create mode 100644 src/pal/tests/palsuite/c_runtime/scalbnf/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/scalbnf/test1/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/c_runtime/scalbnf/test1/test1.c create mode 100644 src/pal/tests/palsuite/c_runtime/scalbnf/test1/testinfo.dat diff --git a/src/System.Private.CoreLib/shared/System/Math.cs b/src/System.Private.CoreLib/shared/System/Math.cs index 6227311..41a0806 100644 --- a/src/System.Private.CoreLib/shared/System/Math.cs +++ b/src/System.Private.CoreLib/shared/System/Math.cs @@ -110,6 +110,76 @@ namespace System return ((long)a) * b; } + public static double BitDecrement(double x) + { + var bits = BitConverter.DoubleToInt64Bits(x); + + if (((bits >> 32) & 0x7FF00000) >= 0x7FF00000) + { + // NaN returns NaN + // -Infinity returns -Infinity + // +Infinity returns double.MaxValue + return (bits == 0x7FF00000_00000000) ? double.MaxValue : x; + } + + if (bits == 0x00000000_00000000) + { + // +0.0 returns -double.Epsilon + return -double.Epsilon; + } + + // Negative values need to be incremented + // Positive values need to be decremented + + bits += ((bits < 0) ? +1 : -1); + return BitConverter.Int64BitsToDouble(bits); + } + + public static double BitIncrement(double x) + { + var bits = BitConverter.DoubleToInt64Bits(x); + + if (((bits >> 32) & 0x7FF00000) >= 0x7FF00000) + { + // NaN returns NaN + // -Infinity returns double.MinValue + // +Infinity returns +Infinity + return (bits == unchecked((long)(0xFFF00000_00000000))) ? double.MinValue : x; + } + + if (bits == unchecked((long)(0x80000000_00000000))) + { + // -0.0 returns double.Epsilon + return double.Epsilon; + } + + // Negative values need to be decremented + // Positive values need to be incremented + + bits += ((bits < 0) ? -1 : +1); + return BitConverter.Int64BitsToDouble(bits); + } + + public static unsafe double CopySign(double x, double y) + { + // This method is required to work for all inputs, + // including NaN, so we operate on the raw bits. + + var xbits = BitConverter.DoubleToInt64Bits(x); + var ybits = BitConverter.DoubleToInt64Bits(y); + + // If the sign bits of x and y are not the same, + // flip the sign bit of x and return the new value; + // otherwise, just return x + + if ((xbits ^ ybits) < 0) + { + return BitConverter.Int64BitsToDouble(xbits ^ long.MinValue); + } + + return x; + } + public static int DivRem(int a, int b, out int result) { // TODO https://github.com/dotnet/coreclr/issues/3439: @@ -542,6 +612,11 @@ namespace System return (val1 >= val2) ? val1 : val2; } + public static double MaxMagnitude(double x, double y) + { + return Max(Abs(x), Abs(y)); + } + [NonVersionable] public static byte Min(byte val1, byte val2) { @@ -630,6 +705,11 @@ namespace System return (val1 <= val2) ? val1 : val2; } + public static double MinMagnitude(double x, double y) + { + return Min(Abs(x), Abs(y)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Round(decimal d) { @@ -680,7 +760,7 @@ namespace System flrTempVal -= 1.0; } - return copysign(flrTempVal, a); + return CopySign(flrTempVal, a); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -810,23 +890,6 @@ namespace System return d; } - private static unsafe double copysign(double x, double y) - { - var xbits = BitConverter.DoubleToInt64Bits(x); - var ybits = BitConverter.DoubleToInt64Bits(y); - - // If the sign bits of x and y are not the same, - // flip the sign bit of x and return the new value; - // otherwise, just return x - - if (((xbits ^ ybits) >> 63) != 0) - { - return BitConverter.Int64BitsToDouble(xbits ^ long.MinValue); - } - - return x; - } - private static void ThrowMinMaxException(T min, T max) { throw new ArgumentException(SR.Format(SR.Argument_MinMaxValue, min, max)); diff --git a/src/System.Private.CoreLib/shared/System/MathF.cs b/src/System.Private.CoreLib/shared/System/MathF.cs index 7769023..9eac890 100644 --- a/src/System.Private.CoreLib/shared/System/MathF.cs +++ b/src/System.Private.CoreLib/shared/System/MathF.cs @@ -36,6 +36,76 @@ namespace System return Math.Abs(x); } + public static float BitDecrement(float x) + { + var bits = BitConverter.SingleToInt32Bits(x); + + if ((bits & 0x7F800000) >= 0x7F800000) + { + // NaN returns NaN + // -Infinity returns -Infinity + // +Infinity returns float.MaxValue + return (bits == 0x7F800000) ? float.MaxValue : x; + } + + if (bits == 0x00000000) + { + // +0.0 returns -float.Epsilon + return -float.Epsilon; + } + + // Negative values need to be incremented + // Positive values need to be decremented + + bits += ((bits < 0) ? +1 : -1); + return BitConverter.Int32BitsToSingle(bits); + } + + public static float BitIncrement(float x) + { + var bits = BitConverter.SingleToInt32Bits(x); + + if ((bits & 0x7F800000) >= 0x7F800000) + { + // NaN returns NaN + // -Infinity returns float.MinValue + // +Infinity returns +Infinity + return (bits == unchecked((int)(0xFF800000))) ? float.MinValue : x; + } + + if (bits == unchecked((int)(0x80000000))) + { + // -0.0 returns float.Epsilon + return float.Epsilon; + } + + // Negative values need to be decremented + // Positive values need to be incremented + + bits += ((bits < 0) ? -1 : +1); + return BitConverter.Int32BitsToSingle(bits); + } + + public static unsafe float CopySign(float x, float y) + { + // This method is required to work for all inputs, + // including NaN, so we operate on the raw bits. + + var xbits = BitConverter.SingleToInt32Bits(x); + var ybits = BitConverter.SingleToInt32Bits(y); + + // If the sign bits of x and y are not the same, + // flip the sign bit of x and return the new value; + // otherwise, just return x + + if ((xbits ^ ybits) < 0) + { + return BitConverter.Int32BitsToSingle(xbits ^ int.MinValue); + } + + return x; + } + public static float IEEERemainder(float x, float y) { if (float.IsNaN(x)) @@ -118,12 +188,22 @@ namespace System return Math.Max(x, y); } + public static float MaxMagnitude(float x, float y) + { + return Max(Abs(x), Abs(y)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(float x, float y) { return Math.Min(x, y); } + public static float MinMagnitude(float x, float y) + { + return Min(Abs(x), Abs(y)); + } + [Intrinsic] public static float Round(float x) { @@ -214,22 +294,5 @@ namespace System ModF(x, &x); return x; } - - private static unsafe float CopySign(float x, float y) - { - var xbits = BitConverter.SingleToInt32Bits(x); - var ybits = BitConverter.SingleToInt32Bits(y); - - // If the sign bits of x and y are not the same, - // flip the sign bit of x and return the new value; - // otherwise, just return x - - if (((xbits ^ ybits) >> 31) != 0) - { - return BitConverter.Int32BitsToSingle(xbits ^ int.MinValue); - } - - return x; - } } } diff --git a/src/System.Private.CoreLib/src/System/Math.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Math.CoreCLR.cs index e4c85f9..5331353 100644 --- a/src/System.Private.CoreLib/src/System/Math.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Math.CoreCLR.cs @@ -65,15 +65,27 @@ namespace System public static extern double Floor(double d); [MethodImpl(MethodImplOptions.InternalCall)] + public static extern double FusedMultiplyAdd(double x, double y, double z); + + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern int IlogB(double x); + + [MethodImpl(MethodImplOptions.InternalCall)] public static extern double Log(double d); [MethodImpl(MethodImplOptions.InternalCall)] + public static extern double Log2(double x); + + [MethodImpl(MethodImplOptions.InternalCall)] public static extern double Log10(double d); [MethodImpl(MethodImplOptions.InternalCall)] public static extern double Pow(double x, double y); [MethodImpl(MethodImplOptions.InternalCall)] + public static extern double ScaleB(double x, int n); + + [MethodImpl(MethodImplOptions.InternalCall)] public static extern double Sin(double a); [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/src/System.Private.CoreLib/src/System/MathF.CoreCLR.cs b/src/System.Private.CoreLib/src/System/MathF.CoreCLR.cs index 1abc040..fa99f1f 100644 --- a/src/System.Private.CoreLib/src/System/MathF.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/MathF.CoreCLR.cs @@ -56,15 +56,27 @@ namespace System public static extern float Floor(float x); [MethodImpl(MethodImplOptions.InternalCall)] + public static extern float FusedMultiplyAdd(float x, float y, float z); + + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern int IlogB(float x); + + [MethodImpl(MethodImplOptions.InternalCall)] public static extern float Log(float x); [MethodImpl(MethodImplOptions.InternalCall)] + public static extern float Log2(float x); + + [MethodImpl(MethodImplOptions.InternalCall)] public static extern float Log10(float x); [MethodImpl(MethodImplOptions.InternalCall)] public static extern float Pow(float x, float y); [MethodImpl(MethodImplOptions.InternalCall)] + public static extern float ScaleB(float x, int n); + + [MethodImpl(MethodImplOptions.InternalCall)] public static extern float Sin(float x); [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/src/classlibnative/float/floatdouble.cpp b/src/classlibnative/float/floatdouble.cpp index b27ef61..2e4b382 100644 --- a/src/classlibnative/float/floatdouble.cpp +++ b/src/classlibnative/float/floatdouble.cpp @@ -200,6 +200,24 @@ FCIMPL2_VV(double, COMDouble::FMod, double x, double y) return (double)fmod(x, y); FCIMPLEND +/*=====================================FusedMultiplyAdd========================== +** +==============================================================================*/ +FCIMPL3_VVV(double, COMDouble::FusedMultiplyAdd, double x, double y, double z) + FCALL_CONTRACT; + + return (double)fma(x, y, z); +FCIMPLEND + +/*=====================================Ilog2==================================== +** +==============================================================================*/ +FCIMPL1_V(int, COMDouble::IlogB, double x) + FCALL_CONTRACT; + + return (int)ilogb(x); +FCIMPLEND + /*=====================================Log====================================== ** ==============================================================================*/ @@ -209,6 +227,15 @@ FCIMPL1_V(double, COMDouble::Log, double x) return (double)log(x); FCIMPLEND +/*=====================================Log2===================================== +** +==============================================================================*/ +FCIMPL1_V(double, COMDouble::Log2, double x) + FCALL_CONTRACT; + + return (double)log2(x); +FCIMPLEND + /*====================================Log10===================================== ** ==============================================================================*/ @@ -236,6 +263,15 @@ FCIMPL2_VV(double, COMDouble::Pow, double x, double y) return (double)pow(x, y); FCIMPLEND +/*=====================================ScaleB=================================== +** +==============================================================================*/ +FCIMPL2_VI(double, COMDouble::ScaleB, double x, int n) + FCALL_CONTRACT; + + return (double)scalbn(x, n); +FCIMPLEND + /*=====================================Sin====================================== ** ==============================================================================*/ diff --git a/src/classlibnative/float/floatsingle.cpp b/src/classlibnative/float/floatsingle.cpp index 3903bc9..23c1445 100644 --- a/src/classlibnative/float/floatsingle.cpp +++ b/src/classlibnative/float/floatsingle.cpp @@ -187,6 +187,24 @@ FCIMPL2_VV(float, COMSingle::FMod, float x, float y) return (float)fmodf(x, y); FCIMPLEND +/*=====================================FusedMultiplyAdd========================== +** +==============================================================================*/ +FCIMPL3_VVV(float, COMSingle::FusedMultiplyAdd, float x, float y, float z) + FCALL_CONTRACT; + + return (float)fmaf(x, y, z); +FCIMPLEND + +/*=====================================Ilog2==================================== +** +==============================================================================*/ +FCIMPL1_V(int, COMSingle::IlogB, float x) + FCALL_CONTRACT; + + return (int)ilogbf(x); +FCIMPLEND + /*=====================================Log====================================== ** ==============================================================================*/ @@ -196,6 +214,15 @@ FCIMPL1_V(float, COMSingle::Log, float x) return (float)logf(x); FCIMPLEND +/*=====================================Log2===================================== +** +==============================================================================*/ +FCIMPL1_V(float, COMSingle::Log2, float x) + FCALL_CONTRACT; + + return (float)log2f(x); +FCIMPLEND + /*====================================Log10===================================== ** ==============================================================================*/ @@ -223,6 +250,15 @@ FCIMPL2_VV(float, COMSingle::Pow, float x, float y) return (float)powf(x, y); FCIMPLEND +/*=====================================ScaleB=================================== +** +==============================================================================*/ +FCIMPL2_VI(float, COMSingle::ScaleB, float x, int n) + FCALL_CONTRACT; + + return (float)scalbnf(x, n); +FCIMPLEND + /*=====================================Sin====================================== ** ==============================================================================*/ diff --git a/src/classlibnative/inc/floatdouble.h b/src/classlibnative/inc/floatdouble.h index d2c819f..602b45b 100644 --- a/src/classlibnative/inc/floatdouble.h +++ b/src/classlibnative/inc/floatdouble.h @@ -25,10 +25,14 @@ public: FCDECL1_V(static double, Exp, double x); FCDECL1_V(static double, Floor, double x); FCDECL2_VV(static double, FMod, double x, double y); + FCDECL3_VVV(static double, FusedMultiplyAdd, double x, double y, double z); + FCDECL1_V(static int, IlogB, double x); FCDECL1_V(static double, Log, double x); + FCDECL1_V(static double, Log2, double x); FCDECL1_V(static double, Log10, double x); FCDECL2_VI(static double, ModF, double x, double* intptr); FCDECL2_VV(static double, Pow, double x, double y); + FCDECL2_VI(static double, ScaleB, double x, int n); FCDECL1_V(static double, Sin, double x); FCDECL1_V(static double, Sinh, double x); FCDECL1_V(static double, Sqrt, double x); diff --git a/src/classlibnative/inc/floatsingle.h b/src/classlibnative/inc/floatsingle.h index a4f9cb7..f54a650 100644 --- a/src/classlibnative/inc/floatsingle.h +++ b/src/classlibnative/inc/floatsingle.h @@ -25,10 +25,14 @@ public: FCDECL1_V(static float, Exp, float x); FCDECL1_V(static float, Floor, float x); FCDECL2_VV(static float, FMod, float x, float y); + FCDECL3_VVV(static float, FusedMultiplyAdd, float x, float y, float z); + FCDECL1_V(static int, IlogB, float x); FCDECL1_V(static float, Log, float x); + FCDECL1_V(static float, Log2, float x); FCDECL1_V(static float, Log10, float x); FCDECL2_VI(static float, ModF, float x, float* intptr); FCDECL2_VV(static float, Pow, float x, float y); + FCDECL2_VI(static float, ScaleB, float x, int n); FCDECL1_V(static float, Sin, float x); FCDECL1_V(static float, Sinh, float x); FCDECL1_V(static float, Sqrt, float x); diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index 94b78ce..5a91904 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -3964,17 +3964,7 @@ GenTree* Compiler::impMathIntrinsic(CORINFO_METHOD_HANDLE method, GenTree* op2; assert(callType != TYP_STRUCT); - assert((intrinsicID == CORINFO_INTRINSIC_Sin) || intrinsicID == CORINFO_INTRINSIC_Cbrt || - (intrinsicID == CORINFO_INTRINSIC_Sqrt) || (intrinsicID == CORINFO_INTRINSIC_Abs) || - (intrinsicID == CORINFO_INTRINSIC_Cos) || (intrinsicID == CORINFO_INTRINSIC_Round) || - (intrinsicID == CORINFO_INTRINSIC_Cosh) || (intrinsicID == CORINFO_INTRINSIC_Sinh) || - (intrinsicID == CORINFO_INTRINSIC_Tan) || (intrinsicID == CORINFO_INTRINSIC_Tanh) || - (intrinsicID == CORINFO_INTRINSIC_Asin) || (intrinsicID == CORINFO_INTRINSIC_Asinh) || - (intrinsicID == CORINFO_INTRINSIC_Acos) || (intrinsicID == CORINFO_INTRINSIC_Acosh) || - (intrinsicID == CORINFO_INTRINSIC_Atan) || (intrinsicID == CORINFO_INTRINSIC_Atan2) || - (intrinsicID == CORINFO_INTRINSIC_Atanh) || (intrinsicID == CORINFO_INTRINSIC_Log10) || - (intrinsicID == CORINFO_INTRINSIC_Pow) || (intrinsicID == CORINFO_INTRINSIC_Exp) || - (intrinsicID == CORINFO_INTRINSIC_Ceiling) || (intrinsicID == CORINFO_INTRINSIC_Floor)); + assert(IsMathIntrinsic(intrinsicID)); op1 = nullptr; diff --git a/src/jit/lsraxarch.cpp b/src/jit/lsraxarch.cpp index 5c37aba..530a71c 100644 --- a/src/jit/lsraxarch.cpp +++ b/src/jit/lsraxarch.cpp @@ -1797,9 +1797,6 @@ int LinearScan::BuildIntrinsic(GenTree* tree) switch (tree->gtIntrinsic.gtIntrinsicId) { - case CORINFO_INTRINSIC_Sqrt: - break; - case CORINFO_INTRINSIC_Abs: // Abs(float x) = x & 0x7fffffff // Abs(double x) = x & 0x7ffffff ffffffff @@ -1826,6 +1823,7 @@ int LinearScan::BuildIntrinsic(GenTree* tree) break; #endif // _TARGET_X86_ + case CORINFO_INTRINSIC_Sqrt: case CORINFO_INTRINSIC_Round: case CORINFO_INTRINSIC_Ceiling: case CORINFO_INTRINSIC_Floor: diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index 6908040..a7f0ff5 100644 --- a/src/pal/inc/pal.h +++ b/src/pal/inc/pal.h @@ -4158,18 +4158,26 @@ SetThreadIdealProcessorEx( #define asinh PAL_asinh #define atan2 PAL_atan2 #define exp PAL_exp +#define fma PAL_fma +#define ilogb PAL_ilogb #define log PAL_log +#define log2 PAL_log2 #define log10 PAL_log10 #define pow PAL_pow +#define scalbn PAL_scalbn #define acosf PAL_acosf #define acoshf PAL_acoshf #define asinf PAL_asinf #define asinhf PAL_asinhf #define atan2f PAL_atan2f #define expf PAL_expf +#define fmaf PAL_fmaf +#define ilogbf PAL_ilogbf #define logf PAL_logf +#define log2f PAL_log2f #define log10f PAL_log10f #define powf PAL_powf +#define scalbnf PAL_scalbnf #define malloc PAL_malloc #define free PAL_free #define mkstemp PAL_mkstemp @@ -4424,10 +4432,14 @@ PALIMPORT double __cdecl exp(double); PALIMPORT double __cdecl fabs(double); PALIMPORT double __cdecl floor(double); PALIMPORT double __cdecl fmod(double, double); +PALIMPORT double __cdecl fma(double, double, double); +PALIMPORT int __cdecl ilogb(double); PALIMPORT double __cdecl log(double); +PALIMPORT double __cdecl log2(double); PALIMPORT double __cdecl log10(double); PALIMPORT double __cdecl modf(double, double*); PALIMPORT double __cdecl pow(double, double); +PALIMPORT double __cdecl scalbn(double, int); PALIMPORT double __cdecl sin(double); PALIMPORT double __cdecl sinh(double); PALIMPORT double __cdecl sqrt(double); @@ -4452,11 +4464,15 @@ PALIMPORT float __cdecl coshf(float); PALIMPORT float __cdecl expf(float); PALIMPORT float __cdecl fabsf(float); PALIMPORT float __cdecl floorf(float); -PALIMPORT float __cdecl fmodf(float, float); +PALIMPORT float __cdecl fmodf(float, float); +PALIMPORT float __cdecl fmaf(float, float, float); +PALIMPORT int __cdecl ilogbf(float); PALIMPORT float __cdecl logf(float); +PALIMPORT float __cdecl log2f(float); PALIMPORT float __cdecl log10f(float); PALIMPORT float __cdecl modff(float, float*); PALIMPORT float __cdecl powf(float, float); +PALIMPORT float __cdecl scalbnf(float, int); PALIMPORT float __cdecl sinf(float); PALIMPORT float __cdecl sinhf(float); PALIMPORT float __cdecl sqrtf(float); diff --git a/src/pal/src/cruntime/math.cpp b/src/pal/src/cruntime/math.cpp index af2f994..126bbff 100644 --- a/src/pal/src/cruntime/math.cpp +++ b/src/pal/src/cruntime/math.cpp @@ -311,6 +311,44 @@ PALIMPORT double __cdecl PAL_exp(double x) /*++ Function: + fma + +See MSDN. +--*/ +PALIMPORT double __cdecl PAL_fma(double x, double y, double z) +{ + double ret; + PERF_ENTRY(fma); + ENTRY("fma (x=%f, y=%f, z=%f)\n", x, y, z); + + ret = fma(x, y, z); + + LOGEXIT("fma returns double %f\n", ret); + PERF_EXIT(fma); + return ret; +} + +/*++ +Function: + ilogb + +See MSDN. +--*/ +PALIMPORT int __cdecl PAL_ilogb(double x) +{ + int ret; + PERF_ENTRY(ilogb); + ENTRY("ilogb (x=%f)\n", x); + + ret = ilogb(x); + + LOGEXIT("ilogb returns int %d\n", ret); + PERF_EXIT(ilogb); + return ret; +} + +/*++ +Function: labs See MSDN. @@ -360,6 +398,25 @@ PALIMPORT double __cdecl PAL_log(double x) /*++ Function: + log2 + +See MSDN. +--*/ +PALIMPORT double __cdecl PAL_log2(double x) +{ + double ret; + PERF_ENTRY(log2); + ENTRY("log2 (x=%f)\n", x); + + ret = log2(x); + + LOGEXIT("log2 returns double %f\n", ret); + PERF_EXIT(log2); + return ret; +} + +/*++ +Function: log10 See MSDN. @@ -483,6 +540,25 @@ PALIMPORT double __cdecl PAL_pow(double x, double y) /*++ Function: + scalbn + +See MSDN. +--*/ +PALIMPORT double __cdecl PAL_scalbn(double x, int n) +{ + double ret; + PERF_ENTRY(scalbn); + ENTRY("scalbn (x=%f, n=%d)\n", x, n); + + ret = scalbn(x, n); + + LOGEXIT("scalbn returns double %f\n", ret); + PERF_EXIT(scalbn); + return ret; +} + +/*++ +Function: _signbitf Determines whether given single-precision floating point value has a negative sign. @@ -750,6 +826,44 @@ PALIMPORT float __cdecl PAL_expf(float x) /*++ Function: + fmaf + +See MSDN. +--*/ +PALIMPORT float __cdecl PAL_fmaf(float x, float y, float z) +{ + float ret; + PERF_ENTRY(fmaf); + ENTRY("fmaf (x=%f, y=%f, z=%f)\n", x, y, z); + + ret = fmaf(x, y, z); + + LOGEXIT("fma returns float %f\n", ret); + PERF_EXIT(fmaf); + return ret; +} + +/*++ +Function: + ilogbf + +See MSDN. +--*/ +PALIMPORT int __cdecl PAL_ilogbf(float x) +{ + int ret; + PERF_ENTRY(ilogbf); + ENTRY("ilogbf (x=%f)\n", x); + + ret = ilogbf(x); + + LOGEXIT("ilogbf returns int %d\n", ret); + PERF_EXIT(ilogbf); + return ret; +} + +/*++ +Function: logf See MSDN. @@ -780,6 +894,25 @@ PALIMPORT float __cdecl PAL_logf(float x) /*++ Function: + log2f + +See MSDN. +--*/ +PALIMPORT float __cdecl PAL_log2f(float x) +{ + float ret; + PERF_ENTRY(log2f); + ENTRY("log2f (x=%f)\n", x); + + ret = log2f(x); + + LOGEXIT("log2f returns float %f\n", ret); + PERF_EXIT(log2f); + return ret; +} + +/*++ +Function: log10f See MSDN. @@ -894,3 +1027,22 @@ PALIMPORT float __cdecl PAL_powf(float x, float y) PERF_EXIT(powf); return ret; } + +/*++ +Function: + scalbnf + +See MSDN. +--*/ +PALIMPORT float __cdecl PAL_scalbnf(float x, int n) +{ + float ret; + PERF_ENTRY(scalbnf); + ENTRY("scalbnf (x=%f, n=%d)\n", x, n); + + ret = scalbnf(x, n); + + LOGEXIT("scalbnf returns double %f\n", ret); + PERF_EXIT(scalbnf); + return ret; +} diff --git a/src/pal/src/include/pal/palinternal.h b/src/pal/src/include/pal/palinternal.h index 69e4f5f..0e37ba8 100644 --- a/src/pal/src/include/pal/palinternal.h +++ b/src/pal/src/include/pal/palinternal.h @@ -461,10 +461,14 @@ function_name() to call the system's implementation #undef fabs #undef floor #undef fmod +#undef fma +#undef ilogb #undef log +#undef log2 #undef log10 #undef modf #undef pow +#undef scalbn #undef sin #undef sinh #undef sqrt @@ -485,10 +489,14 @@ function_name() to call the system's implementation #undef fabsf #undef floorf #undef fmodf +#undef fmaf +#undef ilogbf #undef logf +#undef log2f #undef log10f #undef modff #undef powf +#undef scalbnf #undef sinf #undef sinhf #undef sqrtf diff --git a/src/pal/tests/palsuite/c_runtime/fma/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fma/CMakeLists.txt new file mode 100644 index 0000000..5e1ef7f --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fma/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) diff --git a/src/pal/tests/palsuite/c_runtime/fma/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fma/test1/CMakeLists.txt new file mode 100644 index 0000000..bb478cb --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fma/test1/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + test1.cpp +) + +add_executable(paltest_fma_test1 + ${SOURCES} +) + +add_dependencies(paltest_fma_test1 coreclrpal) + +target_link_libraries(paltest_fma_test1 + ${COMMON_TEST_LIBRARIES} +) diff --git a/src/pal/tests/palsuite/c_runtime/fma/test1/test1.cpp b/src/pal/tests/palsuite/c_runtime/fma/test1/test1.cpp new file mode 100644 index 0000000..f6918d6 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fma/test1/test1.cpp @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*===================================================================== +** +** Source: test1.c +** +** Purpose: Tests that fma returns correct values for a subset of values. +** Tests with positive and negative values of x, y, and z to ensure +** fmaf is returning correct results. +** +**===================================================================*/ + +#include + +// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this +// is slightly too accurate when writing tests meant to run against libm implementations +// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get. +// +// The tests themselves will take PAL_EPSILON and adjust it according to the expected result +// so that the delta used for comparison will compare the most significant digits and ignore +// any digits that are outside the double precision range (15-17 digits). + +// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use +// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx +// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will +// use PAL_EPSILON * 10. +#define PAL_EPSILON 8.8817841970012523e-16 + +#define PAL_NAN sqrt(-1.0) +#define PAL_POSINF -log(0.0) +#define PAL_NEGINF log(0.0) + +/** + * Helper test structure + */ +struct test +{ + double x; /* first component of the value to test the function with */ + double y; /* second component of the value to test the function with */ + double z; /* third component of the value to test the function with */ + double expected; /* expected result */ + double variance; /* maximum delta between the expected and actual result */ +}; + +/** + * validate + * + * test validation function + */ +void __cdecl validate(double x, double y, double z, double expected, double variance) +{ + double result = fma(x, y, z); + + /* + * The test is valid when the difference between result + * and expected is less than or equal to variance + */ + double delta = fabs(result - expected); + + if (delta > variance) + { + Fail("fma(%g, %g, %g) returned %20.17g when it should have returned %20.17g", + x, y, z, result, expected); + } +} + +/** + * validate + * + * test validation function for values returning NaN + */ +void __cdecl validate_isnan(double x, double y, double z) +{ + double result = fma(x, y, z); + + if (!_isnan(result)) + { + Fail("fma(%g, %g, %g) returned %20.17g when it should have returned %20.17g", + x, y, z, result, PAL_NAN); + } +} + +/** + * main + * + * executable entry point + */ +int __cdecl main(int argc, char **argv) +{ + struct test tests[] = + { + /* x y z expected variance */ + { PAL_NEGINF, PAL_NEGINF, PAL_NEGINF, PAL_NEGINF, 0 }, + { -1e308, 2, 1e300, -1e300, 0 }, + { 1e308, 2, -1e300, 1e300, 0 }, + { PAL_POSINF, PAL_POSINF, PAL_POSINF, PAL_POSINF, 0 }, + }; + + if (PAL_Initialize(argc, argv) != 0) + { + return FAIL; + } + + for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++) + { + validate(tests[i].x, tests[i].y, tests[i].z, tests[i].expected, tests[i].variance); + } + + // Returns NaN if x or y is infinite, the other is zero, and z is NaN + validate_isnan(PAL_NEGINF, 0, PAL_NAN); + validate_isnan(PAL_POSINF, 0, PAL_NAN); + validate_isnan(0, PAL_NEGINF, PAL_NAN); + validate_isnan(0, PAL_POSINF, PAL_NAN); + + // Returns NaN if x or y is infinite, the other is zero, and z is not-NaN + validate_isnan(PAL_POSINF, 0, PAL_NEGINF); + validate_isnan(PAL_NEGINF, 0, PAL_NEGINF); + validate_isnan(0, PAL_POSINF, PAL_NEGINF); + validate_isnan(0, PAL_NEGINF, PAL_NEGINF); + + validate_isnan(PAL_POSINF, 0, 0); + validate_isnan(PAL_NEGINF, 0, 0); + validate_isnan(0, PAL_POSINF, 0); + validate_isnan(0, PAL_NEGINF, 0); + + validate_isnan(PAL_POSINF, 0, PAL_POSINF); + validate_isnan(PAL_NEGINF, 0, PAL_POSINF); + validate_isnan(0, PAL_POSINF, PAL_POSINF); + validate_isnan(0, PAL_NEGINF, PAL_POSINF); + + // Returns NaN if (x * y) is infinite, and z is an infinite of the opposite sign + validate_isnan(PAL_POSINF, PAL_POSINF, PAL_NEGINF); + validate_isnan(PAL_NEGINF, PAL_NEGINF, PAL_POSINF); + validate_isnan(PAL_POSINF, PAL_NEGINF, PAL_POSINF); + validate_isnan(PAL_NEGINF, PAL_POSINF, PAL_POSINF); + + validate_isnan(PAL_POSINF, 1, PAL_NEGINF); + validate_isnan(PAL_NEGINF, 1, PAL_POSINF); + validate_isnan(PAL_POSINF, 1, PAL_POSINF); + validate_isnan(PAL_NEGINF, 1, PAL_POSINF); + + validate_isnan(1, PAL_POSINF, PAL_NEGINF); + validate_isnan(1, PAL_NEGINF, PAL_POSINF); + validate_isnan(1, PAL_NEGINF, PAL_POSINF); + validate_isnan(1, PAL_POSINF, PAL_POSINF); + + PAL_Terminate(); + return PASS; +} diff --git a/src/pal/tests/palsuite/c_runtime/fma/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fma/test1/testinfo.dat new file mode 100644 index 0000000..22bf0e7 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fma/test1/testinfo.dat @@ -0,0 +1,17 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = C Runtime +Function = fma +Name = Call fma with some std input/output. +TYPE = DEFAULT +EXE1 = test1 +Description += Call the fma function with various num/exponent pairs += that should produce std answers. + + + + diff --git a/src/pal/tests/palsuite/c_runtime/fmaf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fmaf/CMakeLists.txt new file mode 100644 index 0000000..5e1ef7f --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fmaf/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) diff --git a/src/pal/tests/palsuite/c_runtime/fmaf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fmaf/test1/CMakeLists.txt new file mode 100644 index 0000000..d723d32 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fmaf/test1/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + test1.c +) + +add_executable(paltest_fmaf_test1 + ${SOURCES} +) + +add_dependencies(paltest_fmaf_test1 coreclrpal) + +target_link_libraries(paltest_fmaf_test1 + ${COMMON_TEST_LIBRARIES} +) diff --git a/src/pal/tests/palsuite/c_runtime/fmaf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fmaf/test1/test1.c new file mode 100644 index 0000000..7c3b5e3 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fmaf/test1/test1.c @@ -0,0 +1,150 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*===================================================================== +** +** Source: test1.c +** +** Purpose: Tests that fmaf returns correct values for a subset of values. +** Tests with positive and negative values of x, y, and z to ensure +** fmaf is returning correct results. +** +**===================================================================*/ + +#include + +// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this +// is slightly too accurate when writing tests meant to run against libm implementations +// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get. +// +// The tests themselves will take PAL_EPSILON and adjust it according to the expected result +// so that the delta used for comparison will compare the most significant digits and ignore +// any digits that are outside the double precision range (6-9 digits). + +// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON +// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use +// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10. +#define PAL_EPSILON 4.76837158e-07 + +#define PAL_NAN sqrtf(-1.0f) +#define PAL_POSINF -logf(0.0f) +#define PAL_NEGINF logf(0.0f) + +/** + * Helper test structure + */ +struct test +{ + float x; /* first component of the value to test the function with */ + float y; /* second component of the value to test the function with */ + float z; /* third component of the value to test the function with */ + float expected; /* expected result */ + float variance; /* maximum delta between the expected and actual result */ +}; + +/** + * validate + * + * test validation function + */ +void __cdecl validate(float x, float y, float z, float expected, float variance) +{ + float result = fmaf(x, y, z); + + /* + * The test is valid when the difference between result + * and expected is less than or equal to variance + */ + float delta = fabsf(result - expected); + + if (delta > variance) + { + Fail("fmaf(%g, %g, %g) returned %10.9g when it should have returned %10.9g", + x, y, z, result, expected); + } +} + +/** + * validate + * + * test validation function for values returning NaN + */ +void __cdecl validate_isnan(float x, float y, float z) +{ + float result = fmaf(x, y, z); + + if (!_isnanf(result)) + { + Fail("fmaf(%g, %g, %g) returned %10.9g when it should have returned %10.9g", + x, y, z, result, PAL_NAN); + } +} + +/** + * main + * + * executable entry point + */ +int __cdecl main(int argc, char **argv) +{ + struct test tests[] = + { + /* x y z expected variance */ + { PAL_NEGINF, PAL_NEGINF, PAL_NEGINF, PAL_NEGINF, 0 }, + { -1e38, 2, 1e38, -1e38, 0 }, + { 1e38, 2, -1e38, 1e38, 0 }, + { PAL_POSINF, PAL_POSINF, PAL_POSINF, PAL_POSINF, 0 }, + }; + + if (PAL_Initialize(argc, argv) != 0) + { + return FAIL; + } + + for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++) + { + validate(tests[i].x, tests[i].y, tests[i].z, tests[i].expected, tests[i].variance); + } + + // Returns NaN if x or y is infinite, the other is zero, and z is NaN + validate_isnan(PAL_NEGINF, 0, PAL_NAN); + validate_isnan(PAL_POSINF, 0, PAL_NAN); + validate_isnan(0, PAL_NEGINF, PAL_NAN); + validate_isnan(0, PAL_POSINF, PAL_NAN); + + // Returns NaN if x or y is infinite, the other is zero, and z is not-NaN + validate_isnan(PAL_POSINF, 0, PAL_NEGINF); + validate_isnan(PAL_NEGINF, 0, PAL_NEGINF); + validate_isnan(0, PAL_POSINF, PAL_NEGINF); + validate_isnan(0, PAL_NEGINF, PAL_NEGINF); + + validate_isnan(PAL_POSINF, 0, 0); + validate_isnan(PAL_NEGINF, 0, 0); + validate_isnan(0, PAL_POSINF, 0); + validate_isnan(0, PAL_NEGINF, 0); + + validate_isnan(PAL_POSINF, 0, PAL_POSINF); + validate_isnan(PAL_NEGINF, 0, PAL_POSINF); + validate_isnan(0, PAL_POSINF, PAL_POSINF); + validate_isnan(0, PAL_NEGINF, PAL_POSINF); + + // Returns NaN if (x * y) is infinite, and z is an infinite of the opposite sign + validate_isnan(PAL_POSINF, PAL_POSINF, PAL_NEGINF); + validate_isnan(PAL_NEGINF, PAL_NEGINF, PAL_POSINF); + validate_isnan(PAL_POSINF, PAL_NEGINF, PAL_POSINF); + validate_isnan(PAL_NEGINF, PAL_POSINF, PAL_POSINF); + + validate_isnan(PAL_POSINF, 1, PAL_NEGINF); + validate_isnan(PAL_NEGINF, 1, PAL_POSINF); + validate_isnan(PAL_POSINF, 1, PAL_POSINF); + validate_isnan(PAL_NEGINF, 1, PAL_POSINF); + + validate_isnan(1, PAL_POSINF, PAL_NEGINF); + validate_isnan(1, PAL_NEGINF, PAL_POSINF); + validate_isnan(1, PAL_NEGINF, PAL_POSINF); + validate_isnan(1, PAL_POSINF, PAL_POSINF); + + PAL_Terminate(); + return PASS; +} diff --git a/src/pal/tests/palsuite/c_runtime/fmaf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fmaf/test1/testinfo.dat new file mode 100644 index 0000000..8ca9fb7 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/fmaf/test1/testinfo.dat @@ -0,0 +1,17 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = C Runtime +Function = fmaf +Name = Call fmaf with some std input/output. +TYPE = DEFAULT +EXE1 = test1 +Description += Call the fmaf function with various num/expfonent pairs += that should produce std answers. + + + + diff --git a/src/pal/tests/palsuite/c_runtime/ilogb/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ilogb/CMakeLists.txt new file mode 100644 index 0000000..5e1ef7f --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/ilogb/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) diff --git a/src/pal/tests/palsuite/c_runtime/ilogb/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ilogb/test1/CMakeLists.txt new file mode 100644 index 0000000..8df6908 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/ilogb/test1/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + test1.cpp +) + +add_executable(paltest_ilogb_test1 + ${SOURCES} +) + +add_dependencies(paltest_ilogb_test1 coreclrpal) + +target_link_libraries(paltest_ilogb_test1 + ${COMMON_TEST_LIBRARIES} +) diff --git a/src/pal/tests/palsuite/c_runtime/ilogb/test1/test1.cpp b/src/pal/tests/palsuite/c_runtime/ilogb/test1/test1.cpp new file mode 100644 index 0000000..5df6fcf --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/ilogb/test1/test1.cpp @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*===================================================================== +** +** Source: test1.c +** +** Purpose: Tests that ilogb returns correct values. +** +**===================================================================*/ + +#include + +#define PAL_NAN sqrt(-1.0) +#define PAL_POSINF -log(0.0) +#define PAL_NEGINF log(0.0) + +/** + * Helper test structure + */ +struct test +{ + double value; /* value to test the function with */ + int expected; /* expected result */ +}; + +/** + * validate + * + * test validation function + */ +void __cdecl validate(double value, int expected) +{ + int result = ilogb(value); + + if (result != expected) + { + Fail("ilogb(%g) returned %10.10g when it should have returned %10.10g", + value, result, expected); + } +} + +/** + * main + * + * executable entry point + */ +int __cdecl main(int argc, char **argv) +{ + struct test tests[] = + { + /* value expected */ + { PAL_NEGINF, 0x80000000 }, + { 0, 0x80000000 }, + { PAL_POSINF, 0x80000000 }, + { 0.11331473229676087, -3 }, // expected: -(pi) + { 0.15195522325791297, -2 }, // expected: -(e) + { 0.20269956628651730, -2 }, // expected: -(ln(10)) + { 0.33662253682241906, -1 }, // expected: -(pi / 2) + { 0.36787944117144232, -1 }, // expected: -(log2(e)) + { 0.37521422724648177, -1 }, // expected: -(sqrt(2)) + { 0.45742934732229695, -1 }, // expected: -(2 / sqrt(pi)) + { 0.5, -1 }, // expected: -(1) + { 0.58019181037172444, 0 }, // expected: -(pi / 4) + { 0.61254732653606592, 0 }, // expected: -(1 / sqrt(2)) + { 0.61850313780157598, 0 }, // expected: -(ln(2)) + { 0.64321824193300488, 0 }, // expected: -(2 / pi) + { 0.74005557395545179, 0 }, // expected: -(log10(e)) + { 0.80200887896145195, 0 }, // expected: -(1 / pi) + { 1, 0 }, + { 1.2468689889006383, 0 }, // expected: 1 / pi + { 1.3512498725672678, 0 }, // expected: log10(e) + { 1.5546822754821001, 0 }, // expected: 2 / pi + { 1.6168066722416747, 0 }, // expected: ln(2) + { 1.6325269194381528, 0 }, // expected: 1 / sqrt(2) + { 1.7235679341273495, 0 }, // expected: pi / 4 + { 2, 1 }, + { 2.1861299583286618, 1 }, // expected: 2 / sqrt(pi) + { 2.6651441426902252, 1 }, // expected: sqrt(2) + { 2.7182818284590452, 1 }, // expected: log2(e) value: e + { 2.9706864235520193, 1 }, // expected: pi / 2 + { 4.9334096679145963, 2 }, // expected: ln(10) + { 6.5808859910179210, 2 }, // expected: e + { 8.8249778270762876, 3 }, // expected: pi + { PAL_NAN, 2147483647 }, + }; + + if (PAL_Initialize(argc, argv) != 0) + { + return FAIL; + } + + for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++) + { + validate(tests[i].value, tests[i].expected); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/pal/tests/palsuite/c_runtime/ilogb/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/ilogb/test1/testinfo.dat new file mode 100644 index 0000000..05549db --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/ilogb/test1/testinfo.dat @@ -0,0 +1,17 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = C Runtime +Function = ilogb +Name = Call ilogb with some std input/output. +TYPE = DEFAULT +EXE1 = test1 +Description += Call the ilogb function with various num/exponent pairs += that should produce std answers. + + + + diff --git a/src/pal/tests/palsuite/c_runtime/ilogbf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ilogbf/CMakeLists.txt new file mode 100644 index 0000000..5e1ef7f --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/ilogbf/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) diff --git a/src/pal/tests/palsuite/c_runtime/ilogbf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ilogbf/test1/CMakeLists.txt new file mode 100644 index 0000000..b478f69 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/ilogbf/test1/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + test1.c +) + +add_executable(paltest_ilogbf_test1 + ${SOURCES} +) + +add_dependencies(paltest_ilogbf_test1 coreclrpal) + +target_link_libraries(paltest_ilogbf_test1 + ${COMMON_TEST_LIBRARIES} +) diff --git a/src/pal/tests/palsuite/c_runtime/ilogbf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/ilogbf/test1/test1.c new file mode 100644 index 0000000..2b97e44 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/ilogbf/test1/test1.c @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*===================================================================== +** +** Source: test1.c +** +** Purpose: Tests that ilogbf returns correct values. +** +**===================================================================*/ + +#include + +#define PAL_NAN sqrtf(-1.0f) +#define PAL_POSINF -logf(0.0f) +#define PAL_NEGINF logf(0.0f) + +/** + * Helper test structure + */ +struct test +{ + float value; /* value to test the function with */ + int expected; /* expected result */ +}; + +/** + * validate + * + * test validation function + */ +void __cdecl validate(float value, int expected) +{ + float result = ilogbf(value); + + if (result != expected) + { + Fail("ilogbf(%g) returned %10.10g when it should have returned %10.10g", + value, result, expected); + } +} + +/** + * main + * + * executable entry point + */ +int __cdecl main(int argc, char **argv) +{ + struct test tests[] = + { + /* value expected */ + { PAL_NEGINF, 0x80000000 }, + { 0, 0x80000000 }, + { PAL_POSINF, 0x80000000 }, + { 0.113314732f, -3 }, // expected: -(pi) + { 0.151955223f, -2 }, // expected: -(e) + { 0.202699566f, -2 }, // expected: -(ln(10)) + { 0.336622537f, -1 }, // expected: -(pi / 2) + { 0.367879441f, -1 }, // expected: -(log2(e)) + { 0.375214227f, -1 }, // expected: -(sqrt(2)) + { 0.457429347f, -1 }, // expected: -(2 / sqrt(pi)) + { 0.5f, -1 }, // expected: -(1) + { 0.580191810f, 0 }, // expected: -(pi / 4) + { 0.612547327f, 0 }, // expected: -(1 / sqrt(2)) + { 0.618503138f, 0 }, // expected: -(ln(2)) + { 0.643218242f, 0 }, // expected: -(2 / pi) + { 0.740055574f, 0 }, // expected: -(log10(e)) + { 0.802008879f, 0 }, // expected: -(1 / pi) + { 1, 0 }, + { 1.24686899f, 0 }, // expected: 1 / pi + { 1.35124987f, 0 }, // expected: log10(e) + { 1.55468228f, 0 }, // expected: 2 / pi + { 1.61680667f, 0 }, // expected: ln(2) + { 1.63252692f, 0 }, // expected: 1 / sqrt(2) + { 1.72356793f, 0 }, // expected: pi / 4 + { 2, 1 }, + { 2.18612996f, 1 }, // expected: 2 / sqrt(pi) + { 2.66514414f, 1 }, // expected: sqrt(2) + { 2.71828183f, 1 }, // expected: log2(e) value: e + { 2.97068642f, 1 }, // expected: pi / 2 + { 4.93340967f, 2 }, // expected: ln(10) + { 6.58088599f, 2 }, // expected: e + { 8.82497783f, 3 }, // expected: pi + { PAL_NAN, 2147483647 }, + }; + + if (PAL_Initialize(argc, argv) != 0) + { + return FAIL; + } + + for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++) + { + validate(tests[i].value, tests[i].expected); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/pal/tests/palsuite/c_runtime/ilogbf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/ilogbf/test1/testinfo.dat new file mode 100644 index 0000000..8337bba --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/ilogbf/test1/testinfo.dat @@ -0,0 +1,17 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = C Runtime +Function = ilogbf +Name = Call ilogbf with some std input/output. +TYPE = DEFAULT +EXE1 = test1 +Description += Call the ilogbf function with various num/expfonent pairs += that should produce std answers. + + + + diff --git a/src/pal/tests/palsuite/c_runtime/log2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/log2/CMakeLists.txt new file mode 100644 index 0000000..5e1ef7f --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/log2/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) diff --git a/src/pal/tests/palsuite/c_runtime/log2/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/log2/test1/CMakeLists.txt new file mode 100644 index 0000000..ea0c178 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/log2/test1/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + test1.cpp +) + +add_executable(paltest_log2_test1 + ${SOURCES} +) + +add_dependencies(paltest_log2_test1 coreclrpal) + +target_link_libraries(paltest_log2_test1 + ${COMMON_TEST_LIBRARIES} +) diff --git a/src/pal/tests/palsuite/c_runtime/log2/test1/test1.cpp b/src/pal/tests/palsuite/c_runtime/log2/test1/test1.cpp new file mode 100644 index 0000000..c7900a0 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/log2/test1/test1.cpp @@ -0,0 +1,139 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*===================================================================== +** +** Source: test1.c +** +** Purpose: Tests that log2 returns correct values. +** +**===================================================================*/ + +#include + +// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this +// is slightly too accurate when writing tests meant to run against libm implementations +// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get. +// +// The tests themselves will take PAL_EPSILON and adjust it according to the expected result +// so that the delta used for comparison will compare the most significant digits and ignore +// any digits that are outside the double precision range (15-17 digits). + +// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use +// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx +// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will +// use PAL_EPSILON * 10. +#define PAL_EPSILON 8.8817841970012523e-16 + +#define PAL_NAN sqrt(-1.0) +#define PAL_POSINF -log(0.0) +#define PAL_NEGINF log(0.0) + +/** + * Helper test structure + */ +struct test +{ + double value; /* value to test the function with */ + double expected; /* expected result */ + double variance; /* maximum delta between the expected and actual result */ +}; + +/** + * validate + * + * test validation function + */ +void __cdecl validate(double value, double expected, double variance) +{ + double result = log2(value); + + /* + * The test is valid when the difference between result + * and expected is less than or equal to variance + */ + double delta = fabs(result - expected); + + if (delta > variance) + { + Fail("log2(%g) returned %20.17g when it should have returned %20.17g", + value, result, expected); + } +} + +/** + * validate + * + * test validation function for values returning NaN + */ +void __cdecl validate_isnan(double value) +{ + double result = log2(value); + + if (!_isnan(result)) + { + Fail("log2(%g) returned %20.17g when it should have returned %20.17g", + value, result, PAL_NAN); + } +} + +/** + * main + * + * executable entry point + */ +int __cdecl main(int argc, char **argv) +{ + struct test tests[] = + { + /* value expected variance */ + { 0, PAL_NEGINF, 0 }, + { 0.11331473229676087, -3.1415926535897932, PAL_EPSILON * 10 }, // expected: -(pi) + { 0.15195522325791297, -2.7182818284590452, PAL_EPSILON * 10 }, // expected: -(e) + { 0.20269956628651730, -2.3025850929940457, PAL_EPSILON * 10 }, // expected: -(ln(10)) + { 0.33662253682241906, -1.5707963267948966, PAL_EPSILON * 10 }, // expected: -(pi / 2) + { 0.36787944117144232, -1.4426950408889634, PAL_EPSILON * 10 }, // expected: -(log2(e)) + { 0.37521422724648177, -1.4142135623730950, PAL_EPSILON * 10 }, // expected: -(sqrt(2)) + { 0.45742934732229695, -1.1283791670955126, PAL_EPSILON * 10 }, // expected: -(2 / sqrt(pi)) + { 0.5, -1, PAL_EPSILON * 10 }, // expected: -(1) + { 0.58019181037172444, -0.78539816339744831, PAL_EPSILON }, // expected: -(pi / 4) + { 0.61254732653606592, -0.70710678118654752, PAL_EPSILON }, // expected: -(1 / sqrt(2)) + { 0.61850313780157598, -0.69314718055994531, PAL_EPSILON }, // expected: -(ln(2)) + { 0.64321824193300488, -0.63661977236758134, PAL_EPSILON }, // expected: -(2 / pi) + { 0.74005557395545179, -0.43429448190325183, PAL_EPSILON }, // expected: -(log10(e)) + { 0.80200887896145195, -0.31830988618379067, PAL_EPSILON }, // expected: -(1 / pi) + { 1, 0, PAL_EPSILON }, + { 1.2468689889006383, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi + { 1.3512498725672678, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e) + { 1.5546822754821001, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi + { 1.6168066722416747, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2) + { 1.6325269194381528, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2) + { 1.7235679341273495, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4 + { 2, 1, PAL_EPSILON * 10 }, + { 2.1861299583286618, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi) + { 2.6651441426902252, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2) + { 2.7182818284590452, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e) value: e + { 2.9706864235520193, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2 + { 4.9334096679145963, 2.3025850929940457, PAL_EPSILON * 10 }, // expected: ln(10) + { 6.5808859910179210, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e + { 8.8249778270762876, 3.1415926535897932, PAL_EPSILON * 10 }, // expected: pi + { PAL_POSINF, PAL_POSINF, 0 }, + }; + + if (PAL_Initialize(argc, argv) != 0) + { + return FAIL; + } + + for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++) + { + validate(tests[i].x, tests[i].y, tests[i].z, tests[i].expected, tests[i].variance); + } + + validate_isnan(PAL_NEGINF); + validate_isnan(PAL_NAN); + + PAL_Terminate(); + return PASS; +} diff --git a/src/pal/tests/palsuite/c_runtime/log2/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/log2/test1/testinfo.dat new file mode 100644 index 0000000..ef6268e --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/log2/test1/testinfo.dat @@ -0,0 +1,17 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = C Runtime +Function = log2 +Name = Call log2 with some std input/output. +TYPE = DEFAULT +EXE1 = test1 +Description += Call the log2 function with various num/exponent pairs += that should produce std answers. + + + + diff --git a/src/pal/tests/palsuite/c_runtime/log2f/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/log2f/CMakeLists.txt new file mode 100644 index 0000000..5e1ef7f --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/log2f/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) diff --git a/src/pal/tests/palsuite/c_runtime/log2f/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/log2f/test1/CMakeLists.txt new file mode 100644 index 0000000..bee2084 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/log2f/test1/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + test1.c +) + +add_executable(paltest_log2f_test1 + ${SOURCES} +) + +add_dependencies(paltest_log2f_test1 coreclrpal) + +target_link_libraries(paltest_log2f_test1 + ${COMMON_TEST_LIBRARIES} +) diff --git a/src/pal/tests/palsuite/c_runtime/log2f/test1/test1.c b/src/pal/tests/palsuite/c_runtime/log2f/test1/test1.c new file mode 100644 index 0000000..5231aa5 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/log2f/test1/test1.c @@ -0,0 +1,138 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*===================================================================== +** +** Source: test1.c +** +** Purpose: Tests that log2f returns correct values. +** +**===================================================================*/ + +#include + +// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this +// is slightly too accurate when writing tests meant to run against libm implementations +// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get. +// +// The tests themselves will take PAL_EPSILON and adjust it according to the expected result +// so that the delta used for comparison will compare the most significant digits and ignore +// any digits that are outside the double precision range (6-9 digits). + +// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON +// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use +// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10. +#define PAL_EPSILON 4.76837158e-07 + +#define PAL_NAN sqrtf(-1.0f) +#define PAL_POSINF -logf(0.0f) +#define PAL_NEGINF logf(0.0f) + +/** + * Helper test structure + */ +struct test +{ + float value; /* value to test the function with */ + float expected; /* expected result */ + float variance; /* maximum delta between the expected and actual result */ +}; + +/** + * validate + * + * test validation function + */ +void __cdecl validate(float value, float expected, float variance) +{ + float result = log2f(value); + + /* + * The test is valid when the difference between result + * and expected is less than or equal to variance + */ + float delta = fabsf(result - expected); + + if (delta > variance) + { + Fail("log2f(%g) returned %10.9g when it should have returned %10.9g", + value, result, expected); + } +} + +/** + * validate + * + * test validation function for values returning NaN + */ +void __cdecl validate_isnan(float value) +{ + float result = log2f(value); + + if (!_isnanf(result)) + { + Fail("log2f(%g) returned %10.9g when it should have returned %10.9g", + value, result, PAL_NAN); + } +} + +/** + * main + * + * executable entry point + */ +int __cdecl main(int argc, char **argv) +{ + struct test tests[] = + { + /* value expected variance */ + { 0, PAL_NEGINF, 0 }, + { 0.113314732f, -3.14159265f, PAL_EPSILON * 10 }, // expected: -(pi) + { 0.151955223f, -2.71828183f, PAL_EPSILON * 10 }, // expected: -(e) + { 0.202699566f, -2.30258509f, PAL_EPSILON * 10 }, // expected: -(ln(10)) + { 0.336622537f, -1.57079633f, PAL_EPSILON * 10 }, // expected: -(pi / 2) + { 0.367879441f, -1.44269504f, PAL_EPSILON * 10 }, // expected: -(logf2(e)) + { 0.375214227f, -1.41421356f, PAL_EPSILON * 10 }, // expected: -(sqrtf(2)) + { 0.457429347f, -1.12837917f, PAL_EPSILON * 10 }, // expected: -(2 / sqrtf(pi)) + { 0.5f, -1, PAL_EPSILON * 10 }, // expected: -(1) + { 0.580191810f, -0.785398163f, PAL_EPSILON }, // expected: -(pi / 4) + { 0.612547327f, -0.707106781f, PAL_EPSILON }, // expected: -(1 / sqrtf(2)) + { 0.618503138f, -0.693147181f, PAL_EPSILON }, // expected: -(ln(2)) + { 0.643218242f, -0.636619772f, PAL_EPSILON }, // expected: -(2 / pi) + { 0.740055574f, -0.434294482f, PAL_EPSILON }, // expected: -(log10f(e)) + { 0.802008879f, -0.318309886f, PAL_EPSILON }, // expected: -(1 / pi) + { 1, 0, PAL_EPSILON }, + { 1.24686899f, 0.318309886f, PAL_EPSILON }, // expected: 1 / pi + { 1.35124987f, 0.434294482f, PAL_EPSILON }, // expected: log10f(e) value: e + { 1.55468228f, 0.636619772f, PAL_EPSILON }, // expected: 2 / pi + { 1.61680667f, 0.693147181f, PAL_EPSILON }, // expected: ln(2) + { 1.63252692f, 0.707106781f, PAL_EPSILON }, // expected: 1 / sqrtf(2) + { 1.72356793f, 0.785398163f, PAL_EPSILON }, // expected: pi / 4 + { 2, 1, PAL_EPSILON * 10 }, + { 2.18612996f, 1.12837917f, PAL_EPSILON * 10 }, // expected: 2 / sqrtf(pi) + { 2.66514414f, 1.41421356f, PAL_EPSILON * 10 }, // expected: sqrtf(2) + { 2.71828183f, 1.44269504f, PAL_EPSILON * 10 }, // expected: logf2(e) + { 2.97068642f, 1.57079633f, PAL_EPSILON * 10 }, // expected: pi / 2 + { 4.93340967f, 2.30258509f, PAL_EPSILON * 10 }, // expected: ln(10) + { 6.58088599f, 2.71828183f, PAL_EPSILON * 10 }, // expected: e + { 8.82497783f, 3.14159265f, PAL_EPSILON * 10 }, // expected: pi + { PAL_POSINF, PAL_POSINF, 0 }, + }; + + if (PAL_Initialize(argc, argv) != 0) + { + return FAIL; + } + + for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++) + { + validate(tests[i].x, tests[i].y, tests[i].z, tests[i].expected, tests[i].variance); + } + + validate_isnan(PAL_NEGINF); + validate_isnan(PAL_NAN); + + PAL_Terminate(); + return PASS; +} diff --git a/src/pal/tests/palsuite/c_runtime/log2f/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/log2f/test1/testinfo.dat new file mode 100644 index 0000000..7627c82 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/log2f/test1/testinfo.dat @@ -0,0 +1,17 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = C Runtime +Function = log2f +Name = Call log2f with some std input/output. +TYPE = DEFAULT +EXE1 = test1 +Description += Call the log2f function with various num/expfonent pairs += that should produce std answers. + + + + diff --git a/src/pal/tests/palsuite/c_runtime/scalbn/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/scalbn/CMakeLists.txt new file mode 100644 index 0000000..5e1ef7f --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/scalbn/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) diff --git a/src/pal/tests/palsuite/c_runtime/scalbn/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/scalbn/test1/CMakeLists.txt new file mode 100644 index 0000000..083cd11 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/scalbn/test1/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + test1.cpp +) + +add_executable(paltest_scalbn_test1 + ${SOURCES} +) + +add_dependencies(paltest_scalbn_test1 coreclrpal) + +target_link_libraries(paltest_scalbn_test1 + ${COMMON_TEST_LIBRARIES} +) diff --git a/src/pal/tests/palsuite/c_runtime/scalbn/test1/test1.cpp b/src/pal/tests/palsuite/c_runtime/scalbn/test1/test1.cpp new file mode 100644 index 0000000..9507cc4 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/scalbn/test1/test1.cpp @@ -0,0 +1,140 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*===================================================================== +** +** Source: test1.c +** +** Purpose: Tests that scalbn returns correct values. +** +**===================================================================*/ + +#include + +// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this +// is slightly too accurate when writing tests meant to run against libm implementations +// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get. +// +// The tests themselves will take PAL_EPSILON and adjust it according to the expected result +// so that the delta used for comparison will compare the most significant digits and ignore +// any digits that are outside the double precision range (15-17 digits). + +// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use +// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx +// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will +// use PAL_EPSILON * 10. +#define PAL_EPSILON 8.8817841970012523e-16 + +#define PAL_NAN sqrt(-1.0) +#define PAL_POSINF -log(0.0) +#define PAL_NEGINF log(0.0) + +/** + * Helper test structure + */ +struct test +{ + double value; /* value to test the function with */ + int exponent; /* exponent to test the function with */ + double expected; /* expected result */ + double variance; /* maximum delta between the expected and actual result */ +}; + +/** + * validate + * + * test validation function + */ +void __cdecl validate(double value, int exponent, double expected, double variance) +{ + double result = scalbn(value, exponent); + + /* + * The test is valid when the difference between result + * and expected is less than or equal to variance + */ + double delta = fabs(result - expected); + + if (delta > variance) + { + Fail("scalbn(%g, %d) returned %20.17g when it should have returned %20.17g\n", + value, exponent, result, expected); + } +} + +/** + * validate + * + * test validation function for values returning NaN + */ +void __cdecl validate_isnan(double value, int exponent) +{ + double result = scalbn(value, exponent); + + if (!_isnan(result)) + { + Fail("scalbn(%g, %d) returned %20.17g when it should have returned %20.17g\n", + value, exponent, result, PAL_NAN); + } +} + +/** + * main + * + * executable entry point + */ +int __cdecl main(int argc, char **argv) +{ + struct test tests[] = + { + /* value exponent expected variance */ + { PAL_NEGINF, 0x80000000, PAL_NEGINF, 0 }, + { 0, 0x80000000, 0, 0 }, + { 0.11331473229676087, -3, 0.014164341537095108, PAL_EPSILON / 10 }, + { 0.15195522325791297, -2, 0.037988805814478242, PAL_EPSILON / 10 }, + { 0.20269956628651730, -2, 0.050674891571629327, PAL_EPSILON / 10 }, + { 0.33662253682241906, -1, 0.16831126841120952, PAL_EPSILON }, + { 0.36787944117144232, -1, 0.18393972058572117, PAL_EPSILON }, + { 0.37521422724648177, -1, 0.1876071136232409, PAL_EPSILON }, + { 0.45742934732229695, -1, 0.22871467366114848, PAL_EPSILON }, + { 0.5, -1, 0.25, PAL_EPSILON }, + { 0.58019181037172444, 0, 0.5801918103717244, PAL_EPSILON }, + { 0.61254732653606592, 0, 0.61254732653606592, PAL_EPSILON }, + { 0.61850313780157598, 0, 0.61850313780157595, PAL_EPSILON }, + { 0.64321824193300488, 0, 0.64321824193300492, PAL_EPSILON }, + { 0.74005557395545179, 0, 0.74005557395545174, PAL_EPSILON }, + { 0.80200887896145195, 0, 0.8020088789614519, PAL_EPSILON }, + { 1, 0, 1, PAL_EPSILON * 10 }, + { 1.2468689889006383, 0, 1.2468689889006384, PAL_EPSILON * 10 }, + { 1.3512498725672678, 0, 1.3512498725672677, PAL_EPSILON * 10 }, + { 1.5546822754821001, 0, 1.5546822754821001, PAL_EPSILON * 10 }, + { 1.6168066722416747, 0, 1.6168066722416747, PAL_EPSILON * 10 }, + { 1.6325269194381528, 0, 1.6325269194381529, PAL_EPSILON * 10 }, + { 1.7235679341273495, 0, 1.7235679341273495, PAL_EPSILON * 10 }, + { 2, 1, 4, PAL_EPSILON * 10 }, + { 2.1861299583286618, 1, 4.3722599166573239, PAL_EPSILON * 10 }, + { 2.6651441426902252, 1, 5.3302882853804503, PAL_EPSILON * 10 }, + { 2.7182818284590452, 1, 5.4365636569180902, PAL_EPSILON * 10 }, + { 2.9706864235520193, 1, 5.9413728471040388, PAL_EPSILON * 10 }, + { 4.9334096679145963, 2, 19.733638671658387, PAL_EPSILON * 100 }, + { 6.5808859910179210, 2, 26.323543964071686, PAL_EPSILON * 100 }, + { 8.8249778270762876, 3, 70.599822616610297, PAL_EPSILON * 100 }, + { PAL_POSINF, 0x80000000, PAL_POSINF, 0 }, + }; + + if (PAL_Initialize(argc, argv) != 0) + { + return FAIL; + } + + for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++) + { + validate(tests[i].value, tests[i].exponent, tests[i].expected, tests[i].variance); + } + + validate_isnan(PAL_NAN, 2147483647); + + PAL_Terminate(); + return PASS; +} diff --git a/src/pal/tests/palsuite/c_runtime/scalbn/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/scalbn/test1/testinfo.dat new file mode 100644 index 0000000..ce98062 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/scalbn/test1/testinfo.dat @@ -0,0 +1,17 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = C Runtime +Function = scalbn +Name = Call scalbn with some std input/output. +TYPE = DEFAULT +EXE1 = test1 +Description += Call the scalbn function with various num/exponent pairs += that should produce std answers. + + + + diff --git a/src/pal/tests/palsuite/c_runtime/scalbnf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/scalbnf/CMakeLists.txt new file mode 100644 index 0000000..5e1ef7f --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/scalbnf/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) diff --git a/src/pal/tests/palsuite/c_runtime/scalbnf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/scalbnf/test1/CMakeLists.txt new file mode 100644 index 0000000..e14b54a --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/scalbnf/test1/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + test1.c +) + +add_executable(paltest_scalbnf_test1 + ${SOURCES} +) + +add_dependencies(paltest_scalbnf_test1 coreclrpal) + +target_link_libraries(paltest_scalbnf_test1 + ${COMMON_TEST_LIBRARIES} +) diff --git a/src/pal/tests/palsuite/c_runtime/scalbnf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/scalbnf/test1/test1.c new file mode 100644 index 0000000..88f00a2 --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/scalbnf/test1/test1.c @@ -0,0 +1,139 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*===================================================================== +** +** Source: test1.c +** +** Purpose: Tests that scalbnf returns correct values. +** +**===================================================================*/ + +#include + +// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this +// is slightly too accurate when writing tests meant to run against libm implementations +// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get. +// +// The tests themselves will take PAL_EPSILON and adjust it according to the expected result +// so that the delta used for comparison will compare the most significant digits and ignore +// any digits that are outside the double precision range (6-9 digits). + +// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON +// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use +// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10. +#define PAL_EPSILON 4.76837158e-07 + +#define PAL_NAN sqrtf(-1.0f) +#define PAL_POSINF -logf(0.0f) +#define PAL_NEGINF logf(0.0f) + +/** + * Helper test structure + */ +struct test +{ + float value; /* value to test the function with */ + int exponent; /* exponent to test the function with */ + float expected; /* expected result */ + float variance; /* maximum delta between the expected and actual result */ +}; + +/** + * validate + * + * test validation function + */ +void __cdecl validate(float value, int exponent, float expected, float variance) +{ + float result = scalbnf(value, exponent); + + /* + * The test is valid when the difference between result + * and expected is less than or equal to variance + */ + float delta = fabsf(result - expected); + + if (delta > variance) + { + Fail("scalbnf(%g, %g) returned %10.9g when it should have returned %10.9g", + value, exponent, result, expected); + } +} + +/** + * validate + * + * test validation function for values returning NaN + */ +void __cdecl validate_isnan(float value, int exponent) +{ + float result = scalbnf(value, exponent); + + if (!_isnanf(result)) + { + Fail("scalbnf(%g, %g) returned %10.9g when it should have returned %10.9g", + value, exponent, result, PAL_NAN); + } +} + +/** + * main + * + * executable entry point + */ +int __cdecl main(int argc, char **argv) +{ + struct test tests[] = + { + /* value exponent expected variance */ + { PAL_NEGINF, 0x80000000, PAL_NEGINF, 0 }, + { 0, 0x80000000, 0, 0 }, + { 0.113314732f, -3, 0.0141643415f, PAL_EPSILON / 10 }, + { 0.151955223f, -2, 0.0379888058f, PAL_EPSILON / 10 }, + { 0.202699566f, -2, 0.0506748916f, PAL_EPSILON / 10 }, + { 0.336622537f, -1, 0.168311268f, PAL_EPSILON }, + { 0.367879441f, -1, 0.183939721f, PAL_EPSILON }, + { 0.375214227f, -1, 0.187607114f, PAL_EPSILON }, + { 0.457429347f, -1, 0.228714674f, PAL_EPSILON }, + { 0.5f, -1, 0.25f, PAL_EPSILON }, + { 0.580191810f, 0, 0.580191810f, PAL_EPSILON }, + { 0.612547327f, 0, 0.612547327f, PAL_EPSILON }, + { 0.618503138f, 0, 0.618503138f, PAL_EPSILON }, + { 0.643218242f, 0, 0.643218242f, PAL_EPSILON }, + { 0.740055574f, 0, 0.740055574f, PAL_EPSILON }, + { 0.802008879f, 0, 0.802008879f, PAL_EPSILON }, + { 1, 0, 1, PAL_EPSILON * 10 }, + { 1.24686899f, 0, 1.24686899f, PAL_EPSILON * 10 }, + { 1.35124987f, 0, 1.35124987f, PAL_EPSILON * 10 }, + { 1.55468228f, 0, 1.55468228f, PAL_EPSILON * 10 }, + { 1.61680667f, 0, 1.61680667f, PAL_EPSILON * 10 }, + { 1.63252692f, 0, 1.63252692f, PAL_EPSILON * 10 }, + { 1.72356793f, 0, 1.72356793f, PAL_EPSILON * 10 }, + { 2, 1, 4, PAL_EPSILON * 10 }, + { 2.18612996f, 1, 4.37225992f, PAL_EPSILON * 10 }, + { 2.66514414f, 1, 5.33028829f, PAL_EPSILON * 10 }, + { 2.71828183f, 1, 5.43656366f, PAL_EPSILON * 10 }, + { 2.97068642f, 1, 5.94137285f, PAL_EPSILON * 10 }, + { 4.93340967f, 2, 19.7336387f, PAL_EPSILON * 100 }, + { 6.58088599f, 2, 26.3235440f, PAL_EPSILON * 100 }, + { 8.82497783f, 3, 70.5998226f, PAL_EPSILON * 100 }, + { PAL_POSINF, 0x80000000, PAL_POSINF, 0 }, + }; + + if (PAL_Initialize(argc, argv) != 0) + { + return FAIL; + } + + for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++) + { + validate(tests[i].value, tests[i].exponent, tests[i].expected, tests[i].variance); + } + + validate_isnan(PAL_NAN, 2147483647); + + PAL_Terminate(); + return PASS; +} diff --git a/src/pal/tests/palsuite/c_runtime/scalbnf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/scalbnf/test1/testinfo.dat new file mode 100644 index 0000000..728fafa --- /dev/null +++ b/src/pal/tests/palsuite/c_runtime/scalbnf/test1/testinfo.dat @@ -0,0 +1,17 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = C Runtime +Function = scalbnf +Name = Call scalbnf with some std input/output. +TYPE = DEFAULT +EXE1 = test1 +Description += Call the scalbnf function with various num/expfonent pairs += that should produce std answers. + + + + diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h index e168886..31d3661 100644 --- a/src/vm/ecalllist.h +++ b/src/vm/ecalllist.h @@ -624,10 +624,14 @@ FCFuncStart(gMathFuncs) FCIntrinsic("Exp", COMDouble::Exp, CORINFO_INTRINSIC_Exp) FCIntrinsic("Floor", COMDouble::Floor, CORINFO_INTRINSIC_Floor) FCFuncElement("FMod", COMDouble::FMod) + FCFuncElement("FusedMultiplyAdd", COMDouble::FusedMultiplyAdd) + FCFuncElement("IlogB", COMDouble::IlogB) FCFuncElement("Log", COMDouble::Log) + FCFuncElement("Log2", COMDouble::Log2) FCIntrinsic("Log10", COMDouble::Log10, CORINFO_INTRINSIC_Log10) FCFuncElement("ModF", COMDouble::ModF) FCIntrinsic("Pow", COMDouble::Pow, CORINFO_INTRINSIC_Pow) + FCFuncElement("ScaleB", COMDouble::ScaleB) FCIntrinsic("Sin", COMDouble::Sin, CORINFO_INTRINSIC_Sin) FCIntrinsic("Sinh", COMDouble::Sinh, CORINFO_INTRINSIC_Sinh) FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt) @@ -650,10 +654,14 @@ FCFuncStart(gMathFFuncs) FCIntrinsic("Exp", COMSingle::Exp, CORINFO_INTRINSIC_Exp) FCIntrinsic("Floor", COMSingle::Floor, CORINFO_INTRINSIC_Floor) FCFuncElement("FMod", COMSingle::FMod) + FCFuncElement("FusedMultiplyAdd", COMSingle::FusedMultiplyAdd) + FCFuncElement("IlogB", COMSingle::IlogB) FCFuncElement("Log", COMSingle::Log) + FCFuncElement("Log2", COMSingle::Log2) FCIntrinsic("Log10", COMSingle::Log10, CORINFO_INTRINSIC_Log10) FCFuncElement("ModF", COMSingle::ModF) FCIntrinsic("Pow", COMSingle::Pow, CORINFO_INTRINSIC_Pow) + FCFuncElement("ScaleB", COMSingle::ScaleB) FCIntrinsic("Sin", COMSingle::Sin, CORINFO_INTRINSIC_Sin) FCIntrinsic("Sinh", COMSingle::Sinh, CORINFO_INTRINSIC_Sinh) FCIntrinsic("Sqrt", COMSingle::Sqrt, CORINFO_INTRINSIC_Sqrt) diff --git a/src/vm/fcall.h b/src/vm/fcall.h index 1cf4241..9fb7ba0 100644 --- a/src/vm/fcall.h +++ b/src/vm/fcall.h @@ -413,6 +413,7 @@ LPVOID __FCThrowArgument(LPVOID me, enum RuntimeExceptionKind reKind, LPCWSTR ar #define FCDECL3_IVV(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(int /* EAX */, int /* EDX */, a1, a3, a2) #define FCDECL3_IVI(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(int /* EAX */, a3, a1, a2) #define FCDECL3_VVI(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(int /* EAX */, int /* EDX */, a3, a2, a1) +#define FCDECL3_VVV(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(int /* EAX */, int /* EDX */, int /* ECX */, a3, a2, a1) #define FCDECL4(rettype, funcname, a1, a2, a3, a4) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1, a4, a3) #define FCDECL5(rettype, funcname, a1, a2, a3, a4, a5) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1, a5, a4, a3) #define FCDECL6(rettype, funcname, a1, a2, a3, a4, a5, a6) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1, a6, a5, a4, a3) @@ -444,6 +445,7 @@ LPVOID __FCThrowArgument(LPVOID me, enum RuntimeExceptionKind reKind, LPCWSTR ar #define FCDECL3_IVV(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a1, a3, a2) #define FCDECL3_IVI(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a1, a3, a2) #define FCDECL3_VVI(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a2, a1, a3) +#define FCDECL3_VVV(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a3, a2, a1) #define FCDECL4(rettype, funcname, a1, a2, a3, a4) rettype F_CALL_CONV funcname(a1, a2, a4, a3) #define FCDECL5(rettype, funcname, a1, a2, a3, a4, a5) rettype F_CALL_CONV funcname(a1, a2, a5, a4, a3) #define FCDECL6(rettype, funcname, a1, a2, a3, a4, a5, a6) rettype F_CALL_CONV funcname(a1, a2, a6, a5, a4, a3) @@ -499,6 +501,7 @@ LPVOID __FCThrowArgument(LPVOID me, enum RuntimeExceptionKind reKind, LPCWSTR ar #define FCDECL3_IVV(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a1, a2, a3) #define FCDECL3_IVI(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a1, a2, a3) #define FCDECL3_VVI(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a1, a2, a3) +#define FCDECL3_VVV(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a1, a2, a3) #define FCDECL4(rettype, funcname, a1, a2, a3, a4) rettype F_CALL_CONV funcname(a1, a2, a3, a4) #define FCDECL5(rettype, funcname, a1, a2, a3, a4, a5) rettype F_CALL_CONV funcname(a1, a2, a3, a4, a5) #define FCDECL6(rettype, funcname, a1, a2, a3, a4, a5, a6) rettype F_CALL_CONV funcname(a1, a2, a3, a4, a5, a6) @@ -1009,6 +1012,7 @@ public: #define FCIMPL3_IVV(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(int /* EAX */, int /* EDX */, a1, a3, a2) { FCIMPL_PROLOG(funcname) #define FCIMPL3_IVI(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(int /* EAX */, a3, a1, a2) { FCIMPL_PROLOG(funcname) #define FCIMPL3_VVI(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(int /* EAX */, int /* EDX */, a3, a2, a1) { FCIMPL_PROLOG(funcname) +#define FCIMPL3_VVV(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(int /* EAX */, int /* EDX */, int /* ECX */, a3, a2, a1) { FCIMPL_PROLOG(funcname) #define FCIMPL4(rettype, funcname, a1, a2, a3, a4) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1, a4, a3) { FCIMPL_PROLOG(funcname) #define FCIMPL5(rettype, funcname, a1, a2, a3, a4, a5) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1, a5, a4, a3) { FCIMPL_PROLOG(funcname) #define FCIMPL6(rettype, funcname, a1, a2, a3, a4, a5, a6) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1, a6, a5, a4, a3) { FCIMPL_PROLOG(funcname) @@ -1054,6 +1058,8 @@ public: rettype F_CALL_CONV funcname(a1, a3, a2) { FCIMPL_PROLOG(funcname) #define FCIMPL3_VVI(rettype, funcname, a1, a2, a3) FCSIGCHECK(funcname, #rettype "," "V" #a1 "," "V" #a2 "," #a3) \ rettype F_CALL_CONV funcname(a2, a1, a3) { FCIMPL_PROLOG(funcname) +#define FCIMPL3_VVV(rettype, funcname, a1, a2, a3) FCSIGCHECK(funcname, #rettype "," "V" #a1 "," "V" #a2 "," "V" #a3) \ + rettype F_CALL_CONV funcname(a3, a2, a1) { FCIMPL_PROLOG(funcname) #define FCIMPL4(rettype, funcname, a1, a2, a3, a4) FCSIGCHECK(funcname, #rettype "," #a1 "," #a2 "," #a3 "," #a4) \ rettype F_CALL_CONV funcname(a1, a2, a4, a3) { FCIMPL_PROLOG(funcname) #define FCIMPL5(rettype, funcname, a1, a2, a3, a4, a5) FCSIGCHECK(funcname, #rettype "," #a1 "," #a2 "," #a3 "," #a4 "," #a5) \ @@ -1100,6 +1106,7 @@ public: #define FCIMPL3_VII(rettype, funcname, a1, a2, a3) rettype funcname(a1, a2, a3) { FCIMPL_PROLOG(funcname) #define FCIMPL3_IVI(rettype, funcname, a1, a2, a3) rettype funcname(a1, a2, a3) { FCIMPL_PROLOG(funcname) #define FCIMPL3_VVI(rettype, funcname, a1, a2, a3) rettype funcname(a1, a2, a3) { FCIMPL_PROLOG(funcname) +#define FCIMPL3_VVV(rettype, funcname, a1, a2, a3) rettype funcname(a1, a2, a3) { FCIMPL_PROLOG(funcname) #define FCIMPL4(rettype, funcname, a1, a2, a3, a4) rettype funcname(a1, a2, a3, a4) { FCIMPL_PROLOG(funcname) #define FCIMPL5(rettype, funcname, a1, a2, a3, a4, a5) rettype funcname(a1, a2, a3, a4, a5) { FCIMPL_PROLOG(funcname) #define FCIMPL6(rettype, funcname, a1, a2, a3, a4, a5, a6) rettype funcname(a1, a2, a3, a4, a5, a6) { FCIMPL_PROLOG(funcname) -- 2.7.4