summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTanner Gooding <tagoo@outlook.com>2018-11-05 15:37:36 -0800
committerGitHub <noreply@github.com>2018-11-05 15:37:36 -0800
commit28417584d8e98ae7eac22e92b952778f8ea94047 (patch)
treea6010a24228ca769fc7a6381cbd04b3a762e9219
parentd3a7c973723bf2610c7dcdcd00318c06a72a36f8 (diff)
downloadcoreclr-28417584d8e98ae7eac22e92b952778f8ea94047.tar.gz
coreclr-28417584d8e98ae7eac22e92b952778f8ea94047.tar.bz2
coreclr-28417584d8e98ae7eac22e92b952778f8ea94047.zip
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
-rw-r--r--src/System.Private.CoreLib/shared/System/Math.cs99
-rw-r--r--src/System.Private.CoreLib/shared/System/MathF.cs97
-rw-r--r--src/System.Private.CoreLib/src/System/Math.CoreCLR.cs12
-rw-r--r--src/System.Private.CoreLib/src/System/MathF.CoreCLR.cs12
-rw-r--r--src/classlibnative/float/floatdouble.cpp36
-rw-r--r--src/classlibnative/float/floatsingle.cpp36
-rw-r--r--src/classlibnative/inc/floatdouble.h4
-rw-r--r--src/classlibnative/inc/floatsingle.h4
-rw-r--r--src/jit/importer.cpp12
-rw-r--r--src/jit/lsraxarch.cpp4
-rw-r--r--src/pal/inc/pal.h18
-rw-r--r--src/pal/src/cruntime/math.cpp152
-rw-r--r--src/pal/src/include/pal/palinternal.h8
-rw-r--r--src/pal/tests/palsuite/c_runtime/fma/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/fma/test1/CMakeLists.txt17
-rw-r--r--src/pal/tests/palsuite/c_runtime/fma/test1/test1.cpp151
-rw-r--r--src/pal/tests/palsuite/c_runtime/fma/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmaf/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmaf/test1/CMakeLists.txt17
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmaf/test1/test1.c150
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmaf/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/ilogb/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/ilogb/test1/CMakeLists.txt17
-rw-r--r--src/pal/tests/palsuite/c_runtime/ilogb/test1/test1.cpp101
-rw-r--r--src/pal/tests/palsuite/c_runtime/ilogb/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/ilogbf/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/ilogbf/test1/CMakeLists.txt17
-rw-r--r--src/pal/tests/palsuite/c_runtime/ilogbf/test1/test1.c101
-rw-r--r--src/pal/tests/palsuite/c_runtime/ilogbf/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/log2/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/log2/test1/CMakeLists.txt17
-rw-r--r--src/pal/tests/palsuite/c_runtime/log2/test1/test1.cpp139
-rw-r--r--src/pal/tests/palsuite/c_runtime/log2/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/log2f/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/log2f/test1/CMakeLists.txt17
-rw-r--r--src/pal/tests/palsuite/c_runtime/log2f/test1/test1.c138
-rw-r--r--src/pal/tests/palsuite/c_runtime/log2f/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/scalbn/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/scalbn/test1/CMakeLists.txt17
-rw-r--r--src/pal/tests/palsuite/c_runtime/scalbn/test1/test1.cpp140
-rw-r--r--src/pal/tests/palsuite/c_runtime/scalbn/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/scalbnf/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/scalbnf/test1/CMakeLists.txt17
-rw-r--r--src/pal/tests/palsuite/c_runtime/scalbnf/test1/test1.c139
-rw-r--r--src/pal/tests/palsuite/c_runtime/scalbnf/test1/testinfo.dat17
-rw-r--r--src/vm/ecalllist.h8
-rw-r--r--src/vm/fcall.h7
47 files changed, 1814 insertions, 50 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Math.cs b/src/System.Private.CoreLib/shared/System/Math.cs
index 62273113b5..41a0806aaa 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>(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 7769023acb..9eac890d1f 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 e4c85f92a0..5331353c19 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 1abc040e98..fa99f1f635 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 b27ef61416..2e4b382460 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 3903bc9cd3..23c1445e43 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 d2c819f544..602b45b2f8 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 a4f9cb73df..f54a65028a 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 94b78cee9e..5a91904374 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 5c37aba5c5..530a71cacc 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 690804013e..a7f0ff5d74 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 af2f99416e..126bbff551 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 69e4f5fdb9..0e37ba84c0 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 0000000000..5e1ef7f28b
--- /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 0000000000..bb478cbe06
--- /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 0000000000..f6918d6ffd
--- /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 <palsuite.h>
+
+// 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 0000000000..22bf0e70a1
--- /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 0000000000..5e1ef7f28b
--- /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 0000000000..d723d324d4
--- /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 0000000000..7c3b5e391b
--- /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 <palsuite.h>
+
+// 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 0000000000..8ca9fb7330
--- /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 0000000000..5e1ef7f28b
--- /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 0000000000..8df690836f
--- /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 0000000000..5df6fcf355
--- /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 <palsuite.h>
+
+#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 0000000000..05549dbd2f
--- /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 0000000000..5e1ef7f28b
--- /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 0000000000..b478f698fc
--- /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 0000000000..2b97e444f4
--- /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 <palsuite.h>
+
+#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 0000000000..8337bba44d
--- /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 0000000000..5e1ef7f28b
--- /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 0000000000..ea0c178a47
--- /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 0000000000..c7900a0a93
--- /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 <palsuite.h>
+
+// 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 0000000000..ef6268e079
--- /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 0000000000..5e1ef7f28b
--- /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 0000000000..bee20844ab
--- /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 0000000000..5231aa5fcc
--- /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 <palsuite.h>
+
+// 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 0000000000..7627c825c7
--- /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 0000000000..5e1ef7f28b
--- /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 0000000000..083cd113a4
--- /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 0000000000..9507cc4886
--- /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 <palsuite.h>
+
+// 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 0000000000..ce98062b65
--- /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 0000000000..5e1ef7f28b
--- /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 0000000000..e14b54abae
--- /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 0000000000..88f00a2484
--- /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 <palsuite.h>
+
+// 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 0000000000..728fafabae
--- /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 e168886aca..31d3661d6f 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 1cf42412dd..9fb7ba0322 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)