From 047d4ceed434f1d5dd83a67481e63f7f555f209d Mon Sep 17 00:00:00 2001
From: Tanner Gooding <tagoo@outlook.com>
Date: Thu, 21 Sep 2017 11:35:47 -0700
Subject: [PATCH 1/8] Moving parts of `System.MathF` to be shared with CoreRT.

---
 src/classlibnative/float/floatsingle.cpp      |  37 ++--
 src/classlibnative/inc/floatsingle.h          |   4 +-
 src/jit/importer.cpp                          |  16 +-
 src/jit/namedintrinsiclist.h                  |   3 +-
 src/mscorlib/System.Private.CoreLib.csproj    |   2 +-
 .../System.Private.CoreLib.Shared.projitems   |   1 +
 src/mscorlib/{src => shared}/System/MathF.cs  | 170 ++++++++----------
 src/mscorlib/src/System/MathF.CoreCLR.cs      |  76 ++++++++
 src/vm/ecalllist.h                            |   4 +-
 9 files changed, 183 insertions(+), 130 deletions(-)
 rename src/mscorlib/{src => shared}/System/MathF.cs (54%)
 create mode 100644 src/mscorlib/src/System/MathF.CoreCLR.cs

diff --git a/src/classlibnative/float/floatsingle.cpp b/src/classlibnative/float/floatsingle.cpp
index ba48aea70985..6e5021aedc54 100644
--- a/src/classlibnative/float/floatsingle.cpp
+++ b/src/classlibnative/float/floatsingle.cpp
@@ -130,6 +130,15 @@ FCIMPL1_V(float, COMSingle::Floor, float x)
     return (float)floorf(x);
 FCIMPLEND
 
+/*=====================================FMod=====================================
+**
+==============================================================================*/
+FCIMPL2_VV(float, COMSingle::FMod, float x, float y)
+    FCALL_CONTRACT;
+
+    return (float)fmodf(x, y);
+FCIMPLEND
+
 /*=====================================Log======================================
 **
 ==============================================================================*/
@@ -151,10 +160,10 @@ FCIMPLEND
 /*=====================================ModF=====================================
 **
 ==============================================================================*/
-FCIMPL1(float, COMSingle::ModF, float* iptr)
+FCIMPL2_VV(float, COMSingle::ModF, float x, float* intptr)
     FCALL_CONTRACT;
 
-    return (float)modff(*iptr, iptr);
+    return (float)modff(x, intptr);
 FCIMPLEND
 
 /*=====================================Pow======================================
@@ -166,30 +175,6 @@ FCIMPL2_VV(float, COMSingle::Pow, float x, float y)
     return (float)powf(x, y);
 FCIMPLEND
 
-/*====================================Round=====================================
-**
-==============================================================================*/
-FCIMPL1_V(float, COMSingle::Round, float x)
-    FCALL_CONTRACT;
-
-    // If the number has no fractional part do nothing
-    // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
-    if (x == (float)((INT32)x)) {
-        return x;
-    }
-
-    // We had a number that was equally close to 2 integers.
-    // We need to return the even one.
-
-    float flrTempVal = floorf(x + 0.5f);
-
-    if ((x == (floorf(x) + 0.5f)) && (fmod(flrTempVal, 2.0f) != 0)) {
-        flrTempVal -= 1.0f;
-    }
-
-    return _copysignf(flrTempVal, x);
-FCIMPLEND
-
 /*=====================================Sin======================================
 **
 ==============================================================================*/
diff --git a/src/classlibnative/inc/floatsingle.h b/src/classlibnative/inc/floatsingle.h
index 8296e2d37a77..912278c913e1 100644
--- a/src/classlibnative/inc/floatsingle.h
+++ b/src/classlibnative/inc/floatsingle.h
@@ -20,11 +20,11 @@ class COMSingle {
     FCDECL1_V(static float, Cosh, float x);
     FCDECL1_V(static float, Exp, float x);
     FCDECL1_V(static float, Floor, float x);
+    FCDECL2_VV(static float, FMod, float x, float y);
     FCDECL1_V(static float, Log, float x);
     FCDECL1_V(static float, Log10, float x);
-    FCDECL1(static float, ModF, float* iptr);
+    FCDECL2_VV(static float, ModF, float x, float* intptr);
     FCDECL2_VV(static float, Pow, float x, float y);
-    FCDECL1_V(static float, Round, float x);
     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 ddee0aba5b1e..643d48068197 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -3897,11 +3897,21 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
 
     if ((namespaceName != nullptr) && strcmp(namespaceName, "System") == 0)
     {
-        if ((className != nullptr) && strcmp(className, "Enum") == 0)
+        if (className != nullptr)
         {
-            if ((methodName != nullptr) && strcmp(methodName, "HasFlag") == 0)
+            if (strcmp(className, "Enum") == 0)
             {
-                result = NI_Enum_HasFlag;
+                if ((methodName != nullptr) && strcmp(methodName, "HasFlag") == 0)
+                {
+                    result = NI_Enum_HasFlag;
+                }
+            }
+            else if (strcmp(className, "MathF") == 0)
+            {
+                if ((methodName != nullptr) && strcmp(methodName, "Round") == 0)
+                {
+                    result = NI_MathF_Round;
+                }
             }
         }
     }
diff --git a/src/jit/namedintrinsiclist.h b/src/jit/namedintrinsiclist.h
index cf81afc119da..facb3cf04555 100644
--- a/src/jit/namedintrinsiclist.h
+++ b/src/jit/namedintrinsiclist.h
@@ -10,7 +10,8 @@
 enum NamedIntrinsic
 {
     NI_Illegal      = 0,
-    NI_Enum_HasFlag = 1
+    NI_Enum_HasFlag = 1,
+    NI_MathF_Round  = 2
 };
 
 #endif // _NAMEDINTRINSICLIST_H_
diff --git a/src/mscorlib/System.Private.CoreLib.csproj b/src/mscorlib/System.Private.CoreLib.csproj
index 534fc88a61fb..90294fd527a7 100644
--- a/src/mscorlib/System.Private.CoreLib.csproj
+++ b/src/mscorlib/System.Private.CoreLib.csproj
@@ -330,7 +330,7 @@
     <Compile Include="$(BclSourcesRoot)\System\IntPtr.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Internal.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Math.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\MathF.cs" />
+    <Compile Include="$(BclSourcesRoot)\System\MathF.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\mda.cs" />
     <Compile Include="$(BclSourcesRoot)\System\MissingFieldException.cs" />
     <Compile Include="$(BclSourcesRoot)\System\MissingMemberException.cs" />
diff --git a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
index 095d80963afb..faf6dcca05ea 100644
--- a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
@@ -198,6 +198,7 @@
     <Compile Include="$(MSBuildThisFileDirectory)System\Int32.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Int64.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Lazy.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\MathF.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\MarshalByRefObject.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\MemberAccessException.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Memory.cs" />
diff --git a/src/mscorlib/src/System/MathF.cs b/src/mscorlib/shared/System/MathF.cs
similarity index 54%
rename from src/mscorlib/src/System/MathF.cs
rename to src/mscorlib/shared/System/MathF.cs
index 60669a456152..19089dd220a9 100644
--- a/src/mscorlib/src/System/MathF.cs
+++ b/src/mscorlib/shared/System/MathF.cs
@@ -10,18 +10,17 @@
 
 //This class contains only static members and doesn't require serialization.
 
-using System;
+using System.Diagnostics.Contracts;
 using System.Runtime;
 using System.Runtime.CompilerServices;
-using System.Runtime.ConstrainedExecution;
-using System.Runtime.Versioning;
-using System.Diagnostics.Contracts;
 
 namespace System
 {
-    public static class MathF
+    public static partial class MathF
     {
-        private static float singleRoundLimit = 1e8f;
+        public const float E = 2.71828183f;
+
+        public const float PI = 3.14159265f;
 
         private const int maxRoundingDigits = 6;
 
@@ -30,38 +29,13 @@ public static class MathF
             1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, 1e6f
         };
 
-        public const float PI = 3.14159265f;
-
-        public const float E = 2.71828183f;
-
-        public static float Abs(float x) => Math.Abs(x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Acos(float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Asin(float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Atan(float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Atan2(float y, float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Ceiling(float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Cos(float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Cosh(float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Exp(float x);
+        private static float singleRoundLimit = 1e8f;
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Floor(float x);
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static float Abs(float x)
+        {
+            return Math.Abs(x);
+        }
 
         public static float IEEERemainder(float x, float y)
         {
@@ -114,9 +88,6 @@ public static float IEEERemainder(float x, float y)
             }
         }
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Log(float x);
-
         public static float Log(float x, float y)
         {
             if (float.IsNaN(x))
@@ -142,31 +113,55 @@ public static float Log(float x, float y)
             return Log(x) / Log(y);
         }
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Log10(float x);
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static float Max(float x, float y)
+        {
+            return Math.Max(x, y);
+        }
 
-        public static float Max(float x, float y) => Math.Max(x, y);
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static float Min(float x, float y)
+        {
+            return Math.Min(x, y);
+        }
+
+        [Intrinsic]
+        public static float Round(float x)
+        {
+            // If the number has no fractional part do nothing
+            // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
 
-        public static float Min(float x, float y) => Math.Min(x, y);
+            if (x == (float)((int)x))
+            {
+                return x;
+            }
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Pow(float x, float y);
+            // We had a number that was equally close to 2 integers.
+            // We need to return the even one.
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Round(float x);
+            float flrTempVal = Floor(x + 0.5f);
 
-        public static float Round(float x, int digits)
-        {
-            if ((digits < 0) || (digits > maxRoundingDigits))
+            if ((x == (Floor(x) + 0.5f)) && (FMod(flrTempVal, 2.0f) != 0))
             {
-                throw new ArgumentOutOfRangeException(nameof(digits), SR.ArgumentOutOfRange_RoundingDigits);
+                flrTempVal -= 1.0f;
             }
-            Contract.EndContractBlock();
 
-            return InternalRound(x, digits, MidpointRounding.ToEven);
+            return CopySign(flrTempVal, x);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static float Round(float x, int digits)
+        {
+            return Round(x, digits, MidpointRounding.ToEven);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static float Round(float x, MidpointRounding mode)
+        {
+            return Round(x, 0, mode);
         }
 
-        public static float Round(float x, int digits, MidpointRounding mode)
+        public static unsafe float Round(float x, int digits, MidpointRounding mode)
         {
             if ((digits < 0) || (digits > maxRoundingDigits))
             {
@@ -179,41 +174,6 @@ public static float Round(float x, int digits, MidpointRounding mode)
             }
             Contract.EndContractBlock();
 
-            return InternalRound(x, digits, mode);
-        }
-
-        public static float Round(float x, MidpointRounding mode)
-        {
-            if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero)
-            {
-                throw new ArgumentException(SR.Format(SR.Argument_InvalidEnum, mode, nameof(MidpointRounding)), nameof(mode));
-            }
-            Contract.EndContractBlock();
-
-            return InternalRound(x, 0, mode);
-        }
-
-        public static int Sign(float x) => Math.Sign(x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Sin(float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Sinh(float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Sqrt(float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Tan(float x);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern float Tanh(float x);
-
-        public static float Truncate(float x) => InternalTruncate(x);
-
-        private static unsafe float InternalRound(float x, int digits, MidpointRounding mode)
-        {
             if (Abs(x) < singleRoundLimit)
             {
                 var power10 = roundPower10Single[digits];
@@ -222,7 +182,7 @@ private static unsafe float InternalRound(float x, int digits, MidpointRounding
 
                 if (mode == MidpointRounding.AwayFromZero)
                 {
-                    var fraction = SplitFractionSingle(&x);
+                    var fraction = ModF(x, &x);
 
                     if (Abs(fraction) >= 0.5f)
                     {
@@ -240,13 +200,33 @@ private static unsafe float InternalRound(float x, int digits, MidpointRounding
             return x;
         }
 
-        private unsafe static float InternalTruncate(float x)
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int Sign(float x)
+        {
+            return Math.Sign(x);
+        }
+
+        public static unsafe float Truncate(float x)
         {
-            SplitFractionSingle(&x);
+            ModF(x, &x);
             return x;
         }
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static unsafe extern float SplitFractionSingle(float* 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/mscorlib/src/System/MathF.CoreCLR.cs b/src/mscorlib/src/System/MathF.CoreCLR.cs
new file mode 100644
index 000000000000..0e4dcee73785
--- /dev/null
+++ b/src/mscorlib/src/System/MathF.CoreCLR.cs
@@ -0,0 +1,76 @@
+// 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.
+
+/*============================================================
+**
+** Purpose: Some single-precision floating-point math operations
+**
+===========================================================*/
+
+//This class contains only static members and doesn't require serialization.
+
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+    public static partial class MathF
+    {
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Acos(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Asin(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Atan(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Atan2(float y, float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Ceiling(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Cos(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Cosh(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Exp(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Floor(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Log(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 Sin(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Sinh(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Sqrt(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Tan(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Tanh(float x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float FMod(float x, float y);
+        
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern unsafe float ModF(float x, float* intptr);
+    }
+}
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 6997d0f65cfc..7a1c5b237d80 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -674,13 +674,13 @@ FCFuncStart(gMathFFuncs)
     FCIntrinsic("Cosh", COMSingle::Cosh, CORINFO_INTRINSIC_Cosh)
     FCIntrinsic("Exp", COMSingle::Exp, CORINFO_INTRINSIC_Exp)
     FCIntrinsic("Floor", COMSingle::Floor, CORINFO_INTRINSIC_Floor)
+    FCFuncElement("FMod", COMSingle::FMod)
     FCFuncElement("Log", COMSingle::Log)
     FCIntrinsic("Log10", COMSingle::Log10, CORINFO_INTRINSIC_Log10)
+    FCFuncElement("ModF", COMSingle::ModF)
     FCIntrinsic("Pow", COMSingle::Pow, CORINFO_INTRINSIC_Pow)
-    FCIntrinsic("Round", COMSingle::Round, CORINFO_INTRINSIC_Round)
     FCIntrinsic("Sin", COMSingle::Sin, CORINFO_INTRINSIC_Sin)
     FCIntrinsic("Sinh", COMSingle::Sinh, CORINFO_INTRINSIC_Sinh)
-    FCFuncElement("SplitFractionSingle", COMSingle::ModF)
     FCIntrinsic("Sqrt", COMSingle::Sqrt, CORINFO_INTRINSIC_Sqrt)
     FCIntrinsic("Tan", COMSingle::Tan, CORINFO_INTRINSIC_Tan)
     FCIntrinsic("Tanh", COMSingle::Tanh, CORINFO_INTRINSIC_Tanh)

From d38374dafe7ca8e708624bc5477d07a00d07167c Mon Sep 17 00:00:00 2001
From: Tanner Gooding <tagoo@outlook.com>
Date: Thu, 21 Sep 2017 12:57:39 -0700
Subject: [PATCH 2/8] Moving parts of `System.Math` to be shared with CoreRT.

---
 src/classlibnative/float/floatdouble.cpp      |  37 +-
 src/classlibnative/inc/floatdouble.h          |   4 +-
 src/jit/importer.cpp                          |   7 +
 src/jit/namedintrinsiclist.h                  |   3 +-
 .../System.Private.CoreLib.Shared.projitems   |   1 +
 src/mscorlib/shared/System/Math.cs            | 831 ++++++++++++++++++
 src/mscorlib/src/System/Math.cs               | 715 +--------------
 src/vm/ecalllist.h                            |   4 +-
 8 files changed, 894 insertions(+), 708 deletions(-)
 create mode 100644 src/mscorlib/shared/System/Math.cs

diff --git a/src/classlibnative/float/floatdouble.cpp b/src/classlibnative/float/floatdouble.cpp
index ba90a57f888a..419a88987123 100644
--- a/src/classlibnative/float/floatdouble.cpp
+++ b/src/classlibnative/float/floatdouble.cpp
@@ -132,6 +132,15 @@ FCIMPL1_V(double, COMDouble::Floor, double x)
     return (double)floor(x);
 FCIMPLEND
 
+/*=====================================FMod=====================================
+**
+==============================================================================*/
+FCIMPL2_VV(double, COMDouble::FMod, double x, double y)
+    FCALL_CONTRACT;
+
+    return (double)fmod(x, y);
+FCIMPLEND
+
 /*=====================================Log======================================
 **
 ==============================================================================*/
@@ -153,10 +162,10 @@ FCIMPLEND
 /*=====================================ModF=====================================
 **
 ==============================================================================*/
-FCIMPL1(double, COMDouble::ModF, double* iptr)
+FCIMPL2_VV(double, COMDouble::ModF, double x, double* intptr)
     FCALL_CONTRACT;
 
-    return (double)modf(*iptr, iptr);
+    return (double)modf(x, intptr);
 FCIMPLEND
 
 /*=====================================Pow======================================
@@ -168,30 +177,6 @@ FCIMPL2_VV(double, COMDouble::Pow, double x, double y)
     return (double)pow(x, y);
 FCIMPLEND
 
-/*====================================Round=====================================
-**
-==============================================================================*/
-FCIMPL1_V(double, COMDouble::Round, double x)
-    FCALL_CONTRACT;
-
-    // If the number has no fractional part do nothing
-    // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
-    if (x == (double)((INT64)x)) {
-        return x;
-    }
-
-    // We had a number that was equally close to 2 integers.
-    // We need to return the even one.
-
-    double flrTempVal = floor(x + 0.5);
-
-    if ((x == (floor(x) + 0.5)) && (fmod(flrTempVal, 2.0) != 0)) {
-        flrTempVal -= 1.0;
-    }
-
-    return _copysign(flrTempVal, x);
-FCIMPLEND
-
 /*=====================================Sin======================================
 **
 ==============================================================================*/
diff --git a/src/classlibnative/inc/floatdouble.h b/src/classlibnative/inc/floatdouble.h
index 16403c1f368e..0d195e1ace09 100644
--- a/src/classlibnative/inc/floatdouble.h
+++ b/src/classlibnative/inc/floatdouble.h
@@ -20,11 +20,11 @@ class COMDouble {
     FCDECL1_V(static double, Cosh, double x);
     FCDECL1_V(static double, Exp, double x);
     FCDECL1_V(static double, Floor, double x);
+    FCDECL2_VV(static double, FMod, double x, double y);
     FCDECL1_V(static double, Log, double x);
     FCDECL1_V(static double, Log10, double x);
-    FCDECL1(static double, ModF, double* iptr);
+    FCDECL2_VV(static double, ModF, double x, double* intptr);
     FCDECL2_VV(static double, Pow, double x, double y);
-    FCDECL1_V(static double, Round, double x);
     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/jit/importer.cpp b/src/jit/importer.cpp
index 643d48068197..c6bdb0d53d51 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -3913,6 +3913,13 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
                     result = NI_MathF_Round;
                 }
             }
+            else if (strcmp(clasName, "Math") == 0)
+            {
+                if ((methodName != nullptr) && strcmp(methodName, "Round") == 0)
+                {
+                    result = NI_Math_Round;
+                }
+            }
         }
     }
 
diff --git a/src/jit/namedintrinsiclist.h b/src/jit/namedintrinsiclist.h
index facb3cf04555..2cbdb4596546 100644
--- a/src/jit/namedintrinsiclist.h
+++ b/src/jit/namedintrinsiclist.h
@@ -11,7 +11,8 @@ enum NamedIntrinsic
 {
     NI_Illegal      = 0,
     NI_Enum_HasFlag = 1,
-    NI_MathF_Round  = 2
+    NI_MathF_Round  = 2,
+    NI_Math_Round   = 3
 };
 
 #endif // _NAMEDINTRINSICLIST_H_
diff --git a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
index faf6dcca05ea..9dcde8243629 100644
--- a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
@@ -198,6 +198,7 @@
     <Compile Include="$(MSBuildThisFileDirectory)System\Int32.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Int64.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Lazy.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Math.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\MathF.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\MarshalByRefObject.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\MemberAccessException.cs" />
diff --git a/src/mscorlib/shared/System/Math.cs b/src/mscorlib/shared/System/Math.cs
new file mode 100644
index 000000000000..8c15715a8693
--- /dev/null
+++ b/src/mscorlib/shared/System/Math.cs
@@ -0,0 +1,831 @@
+// 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.
+
+/*============================================================
+**
+**
+**
+** Purpose: Some floating-point math operations
+**
+** 
+===========================================================*/
+
+//This class contains only static members and doesn't require serialization.
+
+using System.Diagnostics.Contracts;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+
+namespace System
+{
+    public static partial class Math
+    {
+        public const double E = 2.7182818284590452354;
+
+        public const double PI = 3.14159265358979323846;
+
+        private const int maxRoundingDigits = 15;
+
+        private static double doubleRoundLimit = 1e16d;
+
+        // This table is required for the Round function which can specify the number of digits to round to
+        private static double[] roundPower10Double = new double[] {
+          1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8,
+          1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15
+        };
+
+        public static short Abs(short value)
+        {
+            return (value >= 0) ? value : AbsHelper(value);
+        }
+
+        public static int Abs(int value)
+        {
+            return (value >= 0) ? value : AbsHelper(value);
+        }
+
+        public static long Abs(long value)
+        {
+            return (value >= 0) ? value : AbsHelper(value);
+        }
+
+        [CLSCompliant(false)]
+        public static sbyte Abs(sbyte value)
+        {
+            return (value >= 0) ? value : AbsHelper(value);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Abs(decimal value)
+        {
+            return decimal.Abs(value);
+        }
+
+        public static long BigMul(int a, int b)
+        {
+            return ((long)a) * b;
+        }
+
+        public static int DivRem(int a, int b, out int result)
+        {
+            // TODO https://github.com/dotnet/coreclr/issues/3439:
+            // Restore to using % and / when the JIT is able to eliminate one of the idivs.
+            // In the meantime, a * and - is measurably faster than an extra /.
+
+            int div = a / b;
+            result = a - (div * b);
+            return div;
+        }
+
+        public static long DivRem(long a, long b, out long result)
+        {
+            // TODO https://github.com/dotnet/coreclr/issues/3439:
+            // Restore to using % and / when the JIT is able to eliminate one of the idivs.
+            // In the meantime, a * and - is measurably faster than an extra /.
+
+            long div = a / b;
+            result = a - (div * b);
+            return div;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Ceiling(decimal d)
+        {
+            return decimal.Ceiling(d);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static byte Clamp(byte value, byte min, byte max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Clamp(decimal value, decimal min, decimal max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static double Clamp(double value, double min, double max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static short Clamp(short value, short min, short max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int Clamp(int value, int min, int max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static long Clamp(long value, long min, long max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static sbyte Clamp(sbyte value, sbyte min, sbyte max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static float Clamp(float value, float min, float max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static ushort Clamp(ushort value, ushort min, ushort max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static uint Clamp(uint value, uint min, uint max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static ulong Clamp(ulong value, ulong min, ulong max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Floor(decimal d)
+        {
+            return decimal.Floor(d);
+        }
+
+        public static double IEEERemainder(double x, double y)
+        {
+            if (double.IsNaN(x))
+            {
+                return x; // IEEE 754-2008: NaN payload must be preserved
+            }
+
+            if (double.IsNaN(y))
+            {
+                return y; // IEEE 754-2008: NaN payload must be preserved
+            }
+
+            var regularMod = x % y;
+
+            if (double.IsNaN(regularMod))
+            {
+                return double.NaN;
+            }
+
+            if ((regularMod == 0) && double.IsNegative(x))
+            {
+                return double.NegativeZero;
+            }
+
+            var alternativeResult = (regularMod - (Abs(y) * Sign(x)));
+
+            if (Abs(alternativeResult) == Abs(regularMod))
+            {
+                var divisionResult = x / y;
+                var roundedResult = Round(divisionResult);
+
+                if (Abs(roundedResult) > Abs(divisionResult))
+                {
+                    return alternativeResult;
+                }
+                else
+                {
+                    return regularMod;
+                }
+            }
+
+            if (Abs(alternativeResult) < Abs(regularMod))
+            {
+                return alternativeResult;
+            }
+            else
+            {
+                return regularMod;
+            }
+        }
+
+        public static double Log(double a, double newBase)
+        {
+            if (double.IsNaN(a))
+            {
+                return a; // IEEE 754-2008: NaN payload must be preserved
+            }
+
+            if (double.IsNaN(newBase))
+            {
+                return newBase; // IEEE 754-2008: NaN payload must be preserved
+            }
+
+            if (newBase == 1)
+            {
+                return double.NaN;
+            }
+
+            if ((a != 1) && ((newBase == 0) || double.IsPositiveInfinity(newBase)))
+            {
+                return double.NaN;
+            }
+
+            return (Log(a) / Log(newBase));
+        }
+
+        [NonVersionable]
+        public static byte Max(byte val1, byte val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Max(decimal val1, decimal val2)
+        {
+            return decimal.Max(val1, val2);
+        }
+
+        public static double Max(double val1, double val2)
+        {
+            if (val1 > val2)
+            {
+                return val1;
+            }
+
+            if (double.IsNaN(val1))
+            {
+                return val1;
+            }
+
+            return val2;
+        }
+
+        [NonVersionable]
+        public static short Max(short val1, short val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [NonVersionable]
+        public static int Max(int val1, int val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [NonVersionable]
+        public static long Max(long val1, long val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static sbyte Max(sbyte val1, sbyte val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+        
+        public static float Max(float val1, float val2)
+        {
+            if (val1 > val2)
+            {
+                return val1;
+            }
+
+            if (float.IsNaN(val1))
+            {
+                return val1;
+            }
+
+            return val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static ushort Max(ushort val1, ushort val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static uint Max(uint val1, uint val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static ulong Max(ulong val1, ulong val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [NonVersionable]
+        public static byte Min(byte val1, byte val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Min(decimal val1, decimal val2)
+        {
+            return decimal.Min(val1, val2);
+        }
+
+        public static double Min(double val1, double val2)
+        {
+            if (val1 < val2)
+            {
+                return val1;
+            }
+
+            if (double.IsNaN(val1))
+            {
+                return val1;
+            }
+
+            return val2;
+        }
+
+        [NonVersionable]
+        public static short Min(short val1, short val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [NonVersionable]
+        public static int Min(int val1, int val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [NonVersionable]
+        public static long Min(long val1, long val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static sbyte Min(sbyte val1, sbyte val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        public static float Min(float val1, float val2)
+        {
+            if (val1 < val2)
+            {
+                return val1;
+            }
+
+            if (float.IsNaN(val1))
+            {
+                return val1;
+            }
+
+            return val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static ushort Min(ushort val1, ushort val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static uint Min(uint val1, uint val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static ulong Min(ulong val1, ulong val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Round(decimal d)
+        {
+            return decimal.Round(d, 0);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Round(decimal d, int decimals)
+        {
+            return decimal.Round(d, decimals);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Round(decimal d, MidpointRounding mode)
+        {
+            return decimal.Round(d, 0, mode);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Round(decimal d, int decimals, MidpointRounding mode)
+        {
+            return decimal.Round(d, decimals, mode);
+        }
+
+        [Intrinsic]
+        public static double Round(double a)
+        {
+            // If the number has no fractional part do nothing
+            // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
+
+            if (a == (double)((long)a))
+            {
+                return a;
+            }
+
+            // We had a number that was equally close to 2 integers.
+            // We need to return the even one.
+
+            double flrTempVal = Floor(a + 0.5);
+
+            if ((a == (Floor(a) + 0.5)) && (fmod(flrTempVal, 2.0) != 0))
+            {
+                flrTempVal -= 1.0;
+            }
+
+            return copysign(flrTempVal, a);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static double Round(double value, int digits)
+        {
+            return Round(value, digits, MidpointRounding.ToEven);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static double Round(double value, MidpointRounding mode)
+        {
+            return Round(value, 0, mode);
+        }
+
+        public static unsafe double Round(double value, int digits, MidpointRounding mode)
+        {
+            if ((digits < 0) || (digits > maxRoundingDigits))
+            {
+                throw new ArgumentOutOfRangeException(nameof(digits), SR.ArgumentOutOfRange_RoundingDigits);
+            }
+
+            if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero)
+            {
+                throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode));
+            }
+            Contract.EndContractBlock();
+
+            if (Abs(value) < doubleRoundLimit)
+            {
+                var power10 = roundPower10Double[digits];
+
+                value *= power10;
+
+                if (mode == MidpointRounding.AwayFromZero)
+                {
+                    var fraction = modf(value, &value);
+
+                    if (Abs(fraction) >= 0.5)
+                    {
+                        value += Sign(fraction);
+                    }
+                }
+                else
+                {
+                    value = Round(value);
+                }
+
+                value /= power10;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int Sign(decimal value)
+        {
+            return decimal.Sign(ref value);
+        }
+
+        public static int Sign(double value)
+        {
+            if (value < 0)
+            {
+                return -1;
+            }
+            else if (value > 0)
+            {
+                return 1;
+            }
+            else if (value == 0)
+            {
+                return 0;
+            }
+
+            throw new ArithmeticException(SR.Arithmetic_NaN);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int Sign(short value)
+        {
+            return Sign((int)value);
+        }
+
+        public static int Sign(int value)
+        {
+            return unchecked(value >> 31 | (int)((uint)-value >> 31));
+        }
+
+        public static int Sign(long value)
+        {
+            return unchecked((int)(value >> 63 | (long)((ulong)-value >> 63)));
+        }
+
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int Sign(sbyte value)
+        {
+            return Sign((int)value);
+        }
+
+        public static int Sign(float value)
+        {
+            if (value < 0)
+            {
+                return -1;
+            }
+            else if (value > 0)
+            {
+                return 1;
+            }
+            else if (value == 0)
+            {
+                return 0;
+            }
+
+            throw new ArithmeticException(SR.Arithmetic_NaN);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static decimal Truncate(decimal d)
+        {
+            return decimal.Truncate(d);
+        }
+
+        public static unsafe double Truncate(double d)
+        {
+            modf(d, &d);
+            return d;
+        }
+
+        private static short AbsHelper(short value)
+        {
+            Contract.Requires(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)");
+
+            if (value == short.MinValue)
+            {
+                throw new OverflowException(SR.Overflow_NegateTwosCompNum);
+            }
+            Contract.EndContractBlock();
+
+            return ((short)(-value));
+        }
+
+        private static int AbsHelper(int value)
+        {
+            Contract.Requires(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)");
+
+            if (value == int.MinValue)
+            {
+                throw new OverflowException(SR.Overflow_NegateTwosCompNum);
+            }
+            Contract.EndContractBlock();
+
+            return -value;
+        }
+
+        private static long AbsHelper(long value)
+        {
+            Contract.Requires(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)");
+
+            if (value == long.MinValue)
+            {
+                throw new OverflowException(SR.Overflow_NegateTwosCompNum);
+            }
+            Contract.EndContractBlock();
+
+            return -value;
+        }
+
+        private static sbyte AbsHelper(sbyte value)
+        {
+            Contract.Requires(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)");
+
+            if (value == sbyte.MinValue)
+            {
+                throw new OverflowException(SR.Overflow_NegateTwosCompNum);
+            }
+            Contract.EndContractBlock();
+
+            return ((sbyte)(-value));
+        }
+
+        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/mscorlib/src/System/Math.cs b/src/mscorlib/src/System/Math.cs
index 33d0f7701376..d5d9c3d92b58 100644
--- a/src/mscorlib/src/System/Math.cs
+++ b/src/mscorlib/src/System/Math.cs
@@ -13,712 +13,73 @@
 
 //This class contains only static members and doesn't require serialization.
 
-using System;
-using System.Runtime;
 using System.Runtime.CompilerServices;
-using System.Runtime.ConstrainedExecution;
-using System.Runtime.Versioning;
-using System.Diagnostics.Contracts;
 
 namespace System
 {
-    public static class Math
+    public static partial class Math
     {
-        private static double doubleRoundLimit = 1e16d;
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Abs(double value);
 
-        private const int maxRoundingDigits = 15;
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Abs(float value);
 
-        // This table is required for the Round function which can specify the number of digits to round to
-        private static double[] roundPower10Double = new double[] {
-          1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8,
-          1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15
-      };
-
-        public const double PI = 3.14159265358979323846;
-        public const double E = 2.7182818284590452354;
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern double Acos(double d);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern double Asin(double d);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern double Atan(double d);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern double Atan2(double y, double x);
 
-        public static Decimal Ceiling(Decimal d)
-        {
-            return Decimal.Ceiling(d);
-        }
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern double Ceiling(double a);
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern double Cos(double d);
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern double Cosh(double value);
 
-        public static Decimal Floor(Decimal d)
-        {
-            return Decimal.Floor(d);
-        }
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Exp(double d);
 
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern double Floor(double d);
 
-        private static unsafe double InternalRound(double value, int digits, MidpointRounding mode)
-        {
-            if (Abs(value) < doubleRoundLimit)
-            {
-                Double power10 = roundPower10Double[digits];
-                value *= power10;
-                if (mode == MidpointRounding.AwayFromZero)
-                {
-                    double fraction = SplitFractionDouble(&value);
-                    if (Abs(fraction) >= 0.5d)
-                    {
-                        value += Sign(fraction);
-                    }
-                }
-                else
-                {
-                    // On X86 this can be inlined to just a few instructions
-                    value = Round(value);
-                }
-                value /= power10;
-            }
-            return value;
-        }
-
-        private unsafe static double InternalTruncate(double d)
-        {
-            SplitFractionDouble(&d);
-            return d;
-        }
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern double Sin(double a);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern double Tan(double a);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern double Sinh(double value);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern double Tanh(double value);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern double Round(double a);
-
-        public static double Round(double value, int digits)
-        {
-            if ((digits < 0) || (digits > maxRoundingDigits))
-                throw new ArgumentOutOfRangeException(nameof(digits), SR.ArgumentOutOfRange_RoundingDigits);
-            Contract.EndContractBlock();
-            return InternalRound(value, digits, MidpointRounding.ToEven);
-        }
-
-        public static double Round(double value, MidpointRounding mode)
-        {
-            return Round(value, 0, mode);
-        }
-
-        public static double Round(double value, int digits, MidpointRounding mode)
-        {
-            if ((digits < 0) || (digits > maxRoundingDigits))
-                throw new ArgumentOutOfRangeException(nameof(digits), SR.ArgumentOutOfRange_RoundingDigits);
-            if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero)
-            {
-                throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode));
-            }
-            Contract.EndContractBlock();
-            return InternalRound(value, digits, mode);
-        }
-
-        public static Decimal Round(Decimal d)
-        {
-            return Decimal.Round(d, 0);
-        }
-
-        public static Decimal Round(Decimal d, int decimals)
-        {
-            return Decimal.Round(d, decimals);
-        }
-
-        public static Decimal Round(Decimal d, MidpointRounding mode)
-        {
-            return Decimal.Round(d, 0, mode);
-        }
-
-        public static Decimal Round(Decimal d, int decimals, MidpointRounding mode)
-        {
-            return Decimal.Round(d, decimals, mode);
-        }
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static unsafe extern double SplitFractionDouble(double* value);
-
-        public static Decimal Truncate(Decimal d)
-        {
-            return Decimal.Truncate(d);
-        }
-
-        public static double Truncate(double d)
-        {
-            return InternalTruncate(d);
-        }
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern double Sqrt(double d);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public static extern double Log(double d);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern double Log10(double d);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern double Exp(double d);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern double Pow(double x, double y);
-
-        public static double IEEERemainder(double x, double y)
-        {
-            if (Double.IsNaN(x))
-            {
-                return x; // IEEE 754-2008: NaN payload must be preserved
-            }
-            if (Double.IsNaN(y))
-            {
-                return y; // IEEE 754-2008: NaN payload must be preserved
-            }
-
-            double regularMod = x % y;
-            if (Double.IsNaN(regularMod))
-            {
-                return Double.NaN;
-            }
-            if (regularMod == 0)
-            {
-                if (Double.IsNegative(x))
-                {
-                    return Double.NegativeZero;
-                }
-            }
-            double alternativeResult;
-            alternativeResult = regularMod - (Math.Abs(y) * Math.Sign(x));
-            if (Math.Abs(alternativeResult) == Math.Abs(regularMod))
-            {
-                double divisionResult = x / y;
-                double roundedResult = Math.Round(divisionResult);
-                if (Math.Abs(roundedResult) > Math.Abs(divisionResult))
-                {
-                    return alternativeResult;
-                }
-                else
-                {
-                    return regularMod;
-                }
-            }
-            if (Math.Abs(alternativeResult) < Math.Abs(regularMod))
-            {
-                return alternativeResult;
-            }
-            else
-            {
-                return regularMod;
-            }
-        }
-
-        /*================================Abs=========================================
-        **Returns the absolute value of it's argument.
-        ============================================================================*/
-        [CLSCompliant(false)]
-        public static sbyte Abs(sbyte value)
-        {
-            if (value >= 0)
-                return value;
-            else
-                return AbsHelper(value);
-        }
-
-        private static sbyte AbsHelper(sbyte value)
-        {
-            Contract.Requires(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)");
-            if (value == SByte.MinValue)
-                throw new OverflowException(SR.Overflow_NegateTwosCompNum);
-            Contract.EndContractBlock();
-            return ((sbyte)(-value));
-        }
-
-        public static short Abs(short value)
-        {
-            if (value >= 0)
-                return value;
-            else
-                return AbsHelper(value);
-        }
-
-        private static short AbsHelper(short value)
-        {
-            Contract.Requires(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)");
-            if (value == Int16.MinValue)
-                throw new OverflowException(SR.Overflow_NegateTwosCompNum);
-            Contract.EndContractBlock();
-            return (short)-value;
-        }
-
-        public static int Abs(int value)
-        {
-            if (value >= 0)
-                return value;
-            else
-                return AbsHelper(value);
-        }
-
-        private static int AbsHelper(int value)
-        {
-            Contract.Requires(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)");
-            if (value == Int32.MinValue)
-                throw new OverflowException(SR.Overflow_NegateTwosCompNum);
-            Contract.EndContractBlock();
-            return -value;
-        }
-
-        public static long Abs(long value)
-        {
-            if (value >= 0)
-                return value;
-            else
-                return AbsHelper(value);
-        }
-
-        private static long AbsHelper(long value)
-        {
-            Contract.Requires(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)");
-            if (value == Int64.MinValue)
-                throw new OverflowException(SR.Overflow_NegateTwosCompNum);
-            Contract.EndContractBlock();
-            return -value;
-        }
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        extern public static float Abs(float value);
-        // This is special code to handle NaN (We need to make sure NaN's aren't 
-        // negated).  In CSharp, the else clause here should always be taken if 
-        // value is NaN, since the normal case is taken if and only if value < 0.
-        // To illustrate this completely, a compiler has translated this into:
-        // "load value; load 0; bge; ret -value ; ret value".  
-        // The bge command branches for comparisons with the unordered NaN.  So 
-        // it runs the else case, which returns +value instead of negating it. 
-        //  return (value < 0) ? -value : value;
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        extern public static double Abs(double value);
-        // This is special code to handle NaN (We need to make sure NaN's aren't 
-        // negated).  In CSharp, the else clause here should always be taken if 
-        // value is NaN, since the normal case is taken if and only if value < 0.
-        // To illustrate this completely, a compiler has translated this into:
-        // "load value; load 0; bge; ret -value ; ret value".  
-        // The bge command branches for comparisons with the unordered NaN.  So 
-        // it runs the else case, which returns +value instead of negating it. 
-        // return (value < 0) ? -value : value;
-
-        public static Decimal Abs(Decimal value)
-        {
-            return Decimal.Abs(value);
-        }
-
-        /*================================MAX=========================================
-        **Returns the larger of val1 and val2
-        ============================================================================*/
-        [CLSCompliant(false)]
-        [System.Runtime.Versioning.NonVersionable]
-        public static sbyte Max(sbyte val1, sbyte val2)
-        {
-            return (val1 >= val2) ? val1 : val2;
-        }
-
-        [System.Runtime.Versioning.NonVersionable]
-        public static byte Max(byte val1, byte val2)
-        {
-            return (val1 >= val2) ? val1 : val2;
-        }
-
-        [System.Runtime.Versioning.NonVersionable]
-        public static short Max(short val1, short val2)
-        {
-            return (val1 >= val2) ? val1 : val2;
-        }
-
-        [CLSCompliant(false)]
-        [System.Runtime.Versioning.NonVersionable]
-        public static ushort Max(ushort val1, ushort val2)
-        {
-            return (val1 >= val2) ? val1 : val2;
-        }
-
-        [System.Runtime.Versioning.NonVersionable]
-        public static int Max(int val1, int val2)
-        {
-            return (val1 >= val2) ? val1 : val2;
-        }
-
-        [CLSCompliant(false)]
-        [System.Runtime.Versioning.NonVersionable]
-        public static uint Max(uint val1, uint val2)
-        {
-            return (val1 >= val2) ? val1 : val2;
-        }
-
-        [System.Runtime.Versioning.NonVersionable]
-        public static long Max(long val1, long val2)
-        {
-            return (val1 >= val2) ? val1 : val2;
-        }
-
-        [CLSCompliant(false)]
-        [System.Runtime.Versioning.NonVersionable]
-        public static ulong Max(ulong val1, ulong val2)
-        {
-            return (val1 >= val2) ? val1 : val2;
-        }
 
-        public static float Max(float val1, float val2)
-        {
-            if (val1 > val2)
-                return val1;
-
-            if (Single.IsNaN(val1))
-                return val1;
-
-            return val2;
-        }
-
-        public static double Max(double val1, double val2)
-        {
-            if (val1 > val2)
-                return val1;
-
-            if (Double.IsNaN(val1))
-                return val1;
-
-            return val2;
-        }
-
-        public static Decimal Max(Decimal val1, Decimal val2)
-        {
-            return Decimal.Max(val1, val2);
-        }
-
-        /*================================MIN=========================================
-        **Returns the smaller of val1 and val2.
-        ============================================================================*/
-        [CLSCompliant(false)]
-        [System.Runtime.Versioning.NonVersionable]
-        public static sbyte Min(sbyte val1, sbyte val2)
-        {
-            return (val1 <= val2) ? val1 : val2;
-        }
-
-        [System.Runtime.Versioning.NonVersionable]
-        public static byte Min(byte val1, byte val2)
-        {
-            return (val1 <= val2) ? val1 : val2;
-        }
-
-        [System.Runtime.Versioning.NonVersionable]
-        public static short Min(short val1, short val2)
-        {
-            return (val1 <= val2) ? val1 : val2;
-        }
-
-        [CLSCompliant(false)]
-        [System.Runtime.Versioning.NonVersionable]
-        public static ushort Min(ushort val1, ushort val2)
-        {
-            return (val1 <= val2) ? val1 : val2;
-        }
-
-        [System.Runtime.Versioning.NonVersionable]
-        public static int Min(int val1, int val2)
-        {
-            return (val1 <= val2) ? val1 : val2;
-        }
-
-        [CLSCompliant(false)]
-        [System.Runtime.Versioning.NonVersionable]
-        public static uint Min(uint val1, uint val2)
-        {
-            return (val1 <= val2) ? val1 : val2;
-        }
-
-        [System.Runtime.Versioning.NonVersionable]
-        public static long Min(long val1, long val2)
-        {
-            return (val1 <= val2) ? val1 : val2;
-        }
-
-        [CLSCompliant(false)]
-        [System.Runtime.Versioning.NonVersionable]
-        public static ulong Min(ulong val1, ulong val2)
-        {
-            return (val1 <= val2) ? val1 : val2;
-        }
-
-        public static float Min(float val1, float val2)
-        {
-            if (val1 < val2)
-                return val1;
-
-            if (Single.IsNaN(val1))
-                return val1;
-
-            return val2;
-        }
-
-        public static double Min(double val1, double val2)
-        {
-            if (val1 < val2)
-                return val1;
-
-            if (Double.IsNaN(val1))
-                return val1;
-
-            return val2;
-        }
-
-        public static Decimal Min(Decimal val1, Decimal val2)
-        {
-            return Decimal.Min(val1, val2);
-        }
-
-        /*=====================================Clamp====================================
-        **
-        ==============================================================================*/
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static Byte Clamp(Byte value, Byte min, Byte max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static Decimal Clamp(Decimal value, Decimal min, Decimal max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static Double Clamp(Double value, Double min, Double max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static Int16 Clamp(Int16 value, Int16 min, Int16 max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static Int32 Clamp(Int32 value, Int32 min, Int32 max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static Int64 Clamp(Int64 value, Int64 min, Int64 max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        [CLSCompliant(false)]
-        public static SByte Clamp(SByte value, SByte min, SByte max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static Single Clamp(Single value, Single min, Single max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        [CLSCompliant(false)]
-        public static UInt16 Clamp(UInt16 value, UInt16 min, UInt16 max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        [CLSCompliant(false)]
-        public static UInt32 Clamp(UInt32 value, UInt32 min, UInt32 max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        [CLSCompliant(false)]
-        public static UInt64 Clamp(UInt64 value, UInt64 min, UInt64 max)
-        {
-            if (min > max)
-                ThrowMinMaxException(min, max);
-            if (value < min)
-                return min;
-            else if (value > max)
-                return max;
-            return value;
-        }
-
-        private static void ThrowMinMaxException<T>(T min, T max)
-        {
-            throw new ArgumentException(SR.Format(SR.Argument_MinMaxValue, min, max));
-        }
-
-        /*=====================================Log======================================
-        **
-        ==============================================================================*/
-        public static double Log(double a, double newBase)
-        {
-            if (Double.IsNaN(a))
-            {
-                return a; // IEEE 754-2008: NaN payload must be preserved
-            }
-            if (Double.IsNaN(newBase))
-            {
-                return newBase; // IEEE 754-2008: NaN payload must be preserved
-            }
-
-            if (newBase == 1)
-                return Double.NaN;
-            if (a != 1 && (newBase == 0 || Double.IsPositiveInfinity(newBase)))
-                return Double.NaN;
-
-            return (Log(a) / Log(newBase));
-        }
-
-
-        // Sign function for VB.  Returns -1, 0, or 1 if the sign of the number
-        // is negative, 0, or positive.  Throws for floating point NaN's.
-        [CLSCompliant(false)]
-        public static int Sign(sbyte value) => Sign((int)value);
-
-        // Sign function for VB.  Returns -1, 0, or 1 if the sign of the number
-        // is negative, 0, or positive.  Throws for floating point NaN's.
-        public static int Sign(short value) => Sign((int)value);
-
-        // Sign function for VB.  Returns -1, 0, or 1 if the sign of the number
-        // is negative, 0, or positive.  Throws for floating point NaN's.
-        public static int Sign(int value) => unchecked(value >> 31 | (int)((uint)-value >> 31));
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Log10(double d);
 
-        public static int Sign(long value) => unchecked((int)(value >> 63 | (long)((ulong)-value >> 63)));
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Pow(double x, double y);
 
-        public static int Sign(float value)
-        {
-            if (value < 0)
-                return -1;
-            else if (value > 0)
-                return 1;
-            else if (value == 0)
-                return 0;
-            throw new ArithmeticException(SR.Arithmetic_NaN);
-        }
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Sin(double a);
 
-        public static int Sign(double value)
-        {
-            if (value < 0)
-                return -1;
-            else if (value > 0)
-                return 1;
-            else if (value == 0)
-                return 0;
-            throw new ArithmeticException(SR.Arithmetic_NaN);
-        }
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Sinh(double value);
 
-        public static int Sign(decimal value) => decimal.Sign(ref value);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Sqrt(double d);
 
-        public static long BigMul(int a, int b)
-        {
-            return ((long)a) * b;
-        }
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Tan(double a);
 
-        public static int DivRem(int a, int b, out int result)
-        {
-            // TODO https://github.com/dotnet/coreclr/issues/3439:
-            // Restore to using % and / when the JIT is able to eliminate one of the idivs.
-            // In the meantime, a * and - is measurably faster than an extra /.
-            int div = a / b;
-            result = a - (div * b);
-            return div;
-        }
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Tanh(double value);
 
-        public static long DivRem(long a, long b, out long result)
-        {
-            // TODO https://github.com/dotnet/coreclr/issues/3439:
-            // Restore to using % and / when the JIT is able to eliminate one of the idivs.
-            // In the meantime, a * and - is measurably faster than an extra /.
-            long div = a / b;
-            result = a - (div * b);
-            return div;
-        }
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern double fmod(double x, double y);
+        
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern unsafe double modf(double x, double* intptr);
     }
 }
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 7a1c5b237d80..3c8378764f63 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -652,13 +652,13 @@ FCFuncStart(gMathFuncs)
     FCIntrinsic("Cosh", COMDouble::Cosh, CORINFO_INTRINSIC_Cosh)
     FCIntrinsic("Exp", COMDouble::Exp, CORINFO_INTRINSIC_Exp)
     FCIntrinsic("Floor", COMDouble::Floor, CORINFO_INTRINSIC_Floor)
+    FCFuncElement("fmod", COMDouble::FMod)
     FCFuncElement("Log", COMDouble::Log)
     FCIntrinsic("Log10", COMDouble::Log10, CORINFO_INTRINSIC_Log10)
+    FCFuncElement("modf", COMDouble::ModF)
     FCIntrinsic("Pow", COMDouble::Pow, CORINFO_INTRINSIC_Pow)
-    FCIntrinsic("Round", COMDouble::Round, CORINFO_INTRINSIC_Round)
     FCIntrinsic("Sin", COMDouble::Sin, CORINFO_INTRINSIC_Sin)
     FCIntrinsic("Sinh", COMDouble::Sinh, CORINFO_INTRINSIC_Sinh)
-    FCFuncElement("SplitFractionDouble", COMDouble::ModF)
     FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt)
     FCIntrinsic("Tan", COMDouble::Tan, CORINFO_INTRINSIC_Tan)
     FCIntrinsic("Tanh", COMDouble::Tanh, CORINFO_INTRINSIC_Tanh)

From 687b880092a0769d0b037faf44893bdf1c05b54c Mon Sep 17 00:00:00 2001
From: Tanner Gooding <tagoo@outlook.com>
Date: Thu, 21 Sep 2017 21:09:51 -0700
Subject: [PATCH 3/8] Updating the new 'Round' named intrinsic to map to the
 legacy 'Round' intrinsic.

---
 src/jit/compiler.h   |   5 +
 src/jit/importer.cpp | 252 ++++++++++++++++++++++++-------------------
 2 files changed, 148 insertions(+), 109 deletions(-)

diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index 0997154b6555..11283c6b47fb 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -3007,6 +3007,11 @@ class Compiler
                             bool                  isJitIntrinsic,
                             CorInfoIntrinsics*    pIntrinsicID,
                             bool*                 isSpecialIntrinsic = nullptr);
+    GenTree* impMathIntrinsic(CORINFO_METHOD_HANDLE method,
+                              CORINFO_SIG_INFO*     sig,
+                              var_types             callType,
+                              CorInfoIntrinsics     intrinsicID,
+                              bool                  tailCall);
     NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method);
     GenTreePtr impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
                                        CORINFO_SIG_INFO*    sig,
diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index c6bdb0d53d51..90432159a5e3 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -3346,7 +3346,6 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr            newobjThis,
         case CORINFO_INTRINSIC_Sqrt:
         case CORINFO_INTRINSIC_Abs:
         case CORINFO_INTRINSIC_Cos:
-        case CORINFO_INTRINSIC_Round:
         case CORINFO_INTRINSIC_Cosh:
         case CORINFO_INTRINSIC_Sinh:
         case CORINFO_INTRINSIC_Tan:
@@ -3360,97 +3359,7 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr            newobjThis,
         case CORINFO_INTRINSIC_Exp:
         case CORINFO_INTRINSIC_Ceiling:
         case CORINFO_INTRINSIC_Floor:
-
-            // These are math intrinsics
-
-            assert(callType != TYP_STRUCT);
-
-            op1 = nullptr;
-
-#if defined(LEGACY_BACKEND)
-            if (IsTargetIntrinsic(intrinsicID))
-#elif !defined(_TARGET_X86_)
-            // Intrinsics that are not implemented directly by target instructions will
-            // be re-materialized as users calls in rationalizer. For prefixed tail calls,
-            // don't do this optimization, because
-            //  a) For back compatibility reasons on desktop.Net 4.6 / 4.6.1
-            //  b) It will be non-trivial task or too late to re-materialize a surviving
-            //     tail prefixed GT_INTRINSIC as tail call in rationalizer.
-            if (!IsIntrinsicImplementedByUserCall(intrinsicID) || !tailCall)
-#else
-            // On x86 RyuJIT, importing intrinsics that are implemented as user calls can cause incorrect calculation
-            // of the depth of the stack if these intrinsics are used as arguments to another call. This causes bad
-            // code generation for certain EH constructs.
-            if (!IsIntrinsicImplementedByUserCall(intrinsicID))
-#endif
-            {
-                switch (sig->numArgs)
-                {
-                    case 1:
-                        op1 = impPopStack().val;
-
-#if FEATURE_X87_DOUBLES
-
-                        // X87 stack doesn't differentiate between float/double
-                        // so it doesn't need a cast, but everybody else does
-                        // Just double check it is at least a FP type
-                        noway_assert(varTypeIsFloating(op1));
-
-#else // FEATURE_X87_DOUBLES
-
-                        if (op1->TypeGet() != callType)
-                        {
-                            op1 = gtNewCastNode(callType, op1, callType);
-                        }
-
-#endif // FEATURE_X87_DOUBLES
-
-                        op1 = new (this, GT_INTRINSIC)
-                            GenTreeIntrinsic(genActualType(callType), op1, intrinsicID, method);
-                        break;
-
-                    case 2:
-                        op2 = impPopStack().val;
-                        op1 = impPopStack().val;
-
-#if FEATURE_X87_DOUBLES
-
-                        // X87 stack doesn't differentiate between float/double
-                        // so it doesn't need a cast, but everybody else does
-                        // Just double check it is at least a FP type
-                        noway_assert(varTypeIsFloating(op2));
-                        noway_assert(varTypeIsFloating(op1));
-
-#else // FEATURE_X87_DOUBLES
-
-                        if (op2->TypeGet() != callType)
-                        {
-                            op2 = gtNewCastNode(callType, op2, callType);
-                        }
-                        if (op1->TypeGet() != callType)
-                        {
-                            op1 = gtNewCastNode(callType, op1, callType);
-                        }
-
-#endif // FEATURE_X87_DOUBLES
-
-                        op1 = new (this, GT_INTRINSIC)
-                            GenTreeIntrinsic(genActualType(callType), op1, op2, intrinsicID, method);
-                        break;
-
-                    default:
-                        NO_WAY("Unsupported number of args for Math Instrinsic");
-                }
-
-#ifndef LEGACY_BACKEND
-                if (IsIntrinsicImplementedByUserCall(intrinsicID))
-                {
-                    op1->gtFlags |= GTF_CALL;
-                }
-#endif
-            }
-
-            retNode = op1;
+            retNode = impMathIntrinsic(method, sig, callType, intrinsicID, tailCall);
             break;
 
 #ifdef _TARGET_XARCH_
@@ -3850,6 +3759,18 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr            newobjThis,
                 break;
             }
 
+            case NI_MathF_Round:
+            case NI_Math_Round:
+            {
+                // Math.Round and MathF.Round used to be a legacy JIT intrinsic. In order
+                // to simplify the transition, we will just treat it as if it was still the
+                // old intrinsic, CORINFO_INTRINSIC_Round. This should end up flowing properly
+                // everywhere else.
+
+                retNode = impMathIntrinsic(method, sig, callType, CORINFO_INTRINSIC_Round, tailCall);
+                break;
+            }
+
             default:
                 break;
         }
@@ -3873,6 +3794,123 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr            newobjThis,
     return retNode;
 }
 
+GenTree* Compiler::impMathIntrinsic(CORINFO_METHOD_HANDLE method,
+                                    CORINFO_SIG_INFO*     sig,
+                                    var_types             callType,
+                                    CorInfoIntrinsics     intrinsicID,
+                                    bool                  tailCall)
+{
+    GenTree* op1;
+    GenTree* op2;
+
+    assert(callType != TYP_STRUCT);
+    assert((intrinsicID == CORINFO_INTRINSIC_Sin)
+        || (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_Acos)
+        || (intrinsicID == CORINFO_INTRINSIC_Atan)
+        || (intrinsicID == CORINFO_INTRINSIC_Atan2)
+        || (intrinsicID == CORINFO_INTRINSIC_Log10)
+        || (intrinsicID == CORINFO_INTRINSIC_Pow)
+        || (intrinsicID == CORINFO_INTRINSIC_Exp)
+        || (intrinsicID == CORINFO_INTRINSIC_Ceiling)
+        || (intrinsicID == CORINFO_INTRINSIC_Floor));
+
+    op1 = nullptr;
+
+#if defined(LEGACY_BACKEND)
+    if (IsTargetIntrinsic(intrinsicID))
+#elif !defined(_TARGET_X86_)
+    // Intrinsics that are not implemented directly by target instructions will
+    // be re-materialized as users calls in rationalizer. For prefixed tail calls,
+    // don't do this optimization, because
+    //  a) For back compatibility reasons on desktop.Net 4.6 / 4.6.1
+    //  b) It will be non-trivial task or too late to re-materialize a surviving
+    //     tail prefixed GT_INTRINSIC as tail call in rationalizer.
+    if (!IsIntrinsicImplementedByUserCall(intrinsicID) || !tailCall)
+#else
+    // On x86 RyuJIT, importing intrinsics that are implemented as user calls can cause incorrect calculation
+    // of the depth of the stack if these intrinsics are used as arguments to another call. This causes bad
+    // code generation for certain EH constructs.
+    if (!IsIntrinsicImplementedByUserCall(intrinsicID))
+#endif
+    {
+        switch (sig->numArgs)
+        {
+            case 1:
+                op1 = impPopStack().val;
+
+#if FEATURE_X87_DOUBLES
+
+                // X87 stack doesn't differentiate between float/double
+                // so it doesn't need a cast, but everybody else does
+                // Just double check it is at least a FP type
+                noway_assert(varTypeIsFloating(op1));
+
+#else // FEATURE_X87_DOUBLES
+
+                if (op1->TypeGet() != callType)
+                {
+                    op1 = gtNewCastNode(callType, op1, callType);
+                }
+
+#endif // FEATURE_X87_DOUBLES
+
+                op1 = new (this, GT_INTRINSIC)
+                GenTreeIntrinsic(genActualType(callType), op1, intrinsicID, method);
+                break;
+
+            case 2:
+                op2 = impPopStack().val;
+                op1 = impPopStack().val;
+
+#if FEATURE_X87_DOUBLES
+
+                // X87 stack doesn't differentiate between float/double
+                // so it doesn't need a cast, but everybody else does
+                // Just double check it is at least a FP type
+                noway_assert(varTypeIsFloating(op2));
+                noway_assert(varTypeIsFloating(op1));
+
+#else // FEATURE_X87_DOUBLES
+
+                if (op2->TypeGet() != callType)
+                {
+                    op2 = gtNewCastNode(callType, op2, callType);
+                }
+                if (op1->TypeGet() != callType)
+                {
+                    op1 = gtNewCastNode(callType, op1, callType);
+                }
+
+#endif // FEATURE_X87_DOUBLES
+
+                op1 = new (this, GT_INTRINSIC)
+                GenTreeIntrinsic(genActualType(callType), op1, op2, intrinsicID, method);
+                break;
+
+            default:
+                NO_WAY("Unsupported number of args for Math Instrinsic");
+        }
+
+#ifndef LEGACY_BACKEND
+        if (IsIntrinsicImplementedByUserCall(intrinsicID))
+        {
+            op1->gtFlags |= GTF_CALL;
+        }
+#endif
+    }
+
+    return op1;
+}
+
 //------------------------------------------------------------------------
 // lookupNamedIntrinsic: map method to jit named intrinsic value
 //
@@ -3895,30 +3933,26 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
     const char* namespaceName = nullptr;
     const char* methodName    = info.compCompHnd->getMethodNameFromMetadata(method, &className, &namespaceName);
 
-    if ((namespaceName != nullptr) && strcmp(namespaceName, "System") == 0)
+    // Currently we only have intrinsics at the method level, so we can check that
+    // namespaceName, className, and methodName are all not null upfront. If this ever
+    // changes (such as if we support all methods in a class as intrinsic), we can reorder
+    // the checks to account for that.
+
+    if ((namespaceName != nullptr) && (className != nullptr) && (methodName != nullptr))
     {
-        if (className != nullptr)
+        if (strcmp(namespaceName, "System") == 0)
         {
-            if (strcmp(className, "Enum") == 0)
+            if ((strcmp(className, "Enum") == 0) && (strcmp(methodName, "HasFlag") == 0))
             {
-                if ((methodName != nullptr) && strcmp(methodName, "HasFlag") == 0)
-                {
-                    result = NI_Enum_HasFlag;
-                }
+                result = NI_Enum_HasFlag;
             }
-            else if (strcmp(className, "MathF") == 0)
+            else if ((strcmp(className, "MathF") == 0) && (strcmp(methodName, "Round") == 0))
             {
-                if ((methodName != nullptr) && strcmp(methodName, "Round") == 0)
-                {
-                    result = NI_MathF_Round;
-                }
+                result = NI_MathF_Round;
             }
-            else if (strcmp(clasName, "Math") == 0)
+            else if ((strcmp(className, "Math") == 0) && (strcmp(methodName, "Round") == 0))
             {
-                if ((methodName != nullptr) && strcmp(methodName, "Round") == 0)
-                {
-                    result = NI_Math_Round;
-                }
+                result = NI_Math_Round;
             }
         }
     }

From 04fdd3db68b5c6681a208b60d7c305fb436c0443 Mon Sep 17 00:00:00 2001
From: Tanner Gooding <tagoo@outlook.com>
Date: Thu, 21 Sep 2017 21:26:22 -0700
Subject: [PATCH 4/8] Adding a message to the Math.Round and MathF.Round
 implementations

---
 src/mscorlib/shared/System/Math.cs  | 5 +++++
 src/mscorlib/shared/System/MathF.cs | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/src/mscorlib/shared/System/Math.cs b/src/mscorlib/shared/System/Math.cs
index 8c15715a8693..6cfca945ae3d 100644
--- a/src/mscorlib/shared/System/Math.cs
+++ b/src/mscorlib/shared/System/Math.cs
@@ -605,6 +605,11 @@ public static decimal Round(decimal d, int decimals, MidpointRounding mode)
         [Intrinsic]
         public static double Round(double a)
         {
+            // ************************************************************************************
+            // IMPORTANT: Do not change this implementation without also updating Math.Round(double),
+            //            FloatingPointUtils::round(double), and FloatingPointUtils::round(float)
+            // ************************************************************************************
+
             // If the number has no fractional part do nothing
             // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
 
diff --git a/src/mscorlib/shared/System/MathF.cs b/src/mscorlib/shared/System/MathF.cs
index 19089dd220a9..f596c5a172a1 100644
--- a/src/mscorlib/shared/System/MathF.cs
+++ b/src/mscorlib/shared/System/MathF.cs
@@ -128,6 +128,11 @@ public static float Min(float x, float y)
         [Intrinsic]
         public static float Round(float x)
         {
+            // ************************************************************************************
+            // IMPORTANT: Do not change this implementation without also updating Math.Round(double),
+            //            FloatingPointUtils::round(double), and FloatingPointUtils::round(float)
+            // ************************************************************************************
+    
             // If the number has no fractional part do nothing
             // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
 

From 76f2ba186e14a35f845fb5e3101e63644a39a3f0 Mon Sep 17 00:00:00 2001
From: Tanner Gooding <tagoo@outlook.com>
Date: Thu, 21 Sep 2017 21:31:30 -0700
Subject: [PATCH 5/8] Applying the code format patch for importer.cpp

---
 src/jit/importer.cpp | 33 +++++++++++----------------------
 1 file changed, 11 insertions(+), 22 deletions(-)

diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index 90432159a5e3..a75535524cf9 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -3804,24 +3804,15 @@ GenTree* Compiler::impMathIntrinsic(CORINFO_METHOD_HANDLE method,
     GenTree* op2;
 
     assert(callType != TYP_STRUCT);
-    assert((intrinsicID == CORINFO_INTRINSIC_Sin)
-        || (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_Acos)
-        || (intrinsicID == CORINFO_INTRINSIC_Atan)
-        || (intrinsicID == CORINFO_INTRINSIC_Atan2)
-        || (intrinsicID == CORINFO_INTRINSIC_Log10)
-        || (intrinsicID == CORINFO_INTRINSIC_Pow)
-        || (intrinsicID == CORINFO_INTRINSIC_Exp)
-        || (intrinsicID == CORINFO_INTRINSIC_Ceiling)
-        || (intrinsicID == CORINFO_INTRINSIC_Floor));
+    assert((intrinsicID == CORINFO_INTRINSIC_Sin) || (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_Acos) || (intrinsicID == CORINFO_INTRINSIC_Atan) ||
+           (intrinsicID == CORINFO_INTRINSIC_Atan2) || (intrinsicID == CORINFO_INTRINSIC_Log10) ||
+           (intrinsicID == CORINFO_INTRINSIC_Pow) || (intrinsicID == CORINFO_INTRINSIC_Exp) ||
+           (intrinsicID == CORINFO_INTRINSIC_Ceiling) || (intrinsicID == CORINFO_INTRINSIC_Floor));
 
     op1 = nullptr;
 
@@ -3863,8 +3854,7 @@ GenTree* Compiler::impMathIntrinsic(CORINFO_METHOD_HANDLE method,
 
 #endif // FEATURE_X87_DOUBLES
 
-                op1 = new (this, GT_INTRINSIC)
-                GenTreeIntrinsic(genActualType(callType), op1, intrinsicID, method);
+                op1 = new (this, GT_INTRINSIC) GenTreeIntrinsic(genActualType(callType), op1, intrinsicID, method);
                 break;
 
             case 2:
@@ -3892,8 +3882,7 @@ GenTree* Compiler::impMathIntrinsic(CORINFO_METHOD_HANDLE method,
 
 #endif // FEATURE_X87_DOUBLES
 
-                op1 = new (this, GT_INTRINSIC)
-                GenTreeIntrinsic(genActualType(callType), op1, op2, intrinsicID, method);
+                op1 = new (this, GT_INTRINSIC) GenTreeIntrinsic(genActualType(callType), op1, op2, intrinsicID, method);
                 break;
 
             default:

From ba7ddb9294aac6df28e208e15bcf84448b915d17 Mon Sep 17 00:00:00 2001
From: Tanner Gooding <tagoo@outlook.com>
Date: Thu, 21 Sep 2017 22:07:00 -0700
Subject: [PATCH 6/8] Fixing up some comments in importer.cpp

---
 src/jit/importer.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index a75535524cf9..a101295ccd38 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -3762,7 +3762,7 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr            newobjThis,
             case NI_MathF_Round:
             case NI_Math_Round:
             {
-                // Math.Round and MathF.Round used to be a legacy JIT intrinsic. In order
+                // Math.Round and MathF.Round used to be a traditional JIT intrinsic. In order
                 // to simplify the transition, we will just treat it as if it was still the
                 // old intrinsic, CORINFO_INTRINSIC_Round. This should end up flowing properly
                 // everywhere else.
@@ -3923,9 +3923,7 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
     const char* methodName    = info.compCompHnd->getMethodNameFromMetadata(method, &className, &namespaceName);
 
     // Currently we only have intrinsics at the method level, so we can check that
-    // namespaceName, className, and methodName are all not null upfront. If this ever
-    // changes (such as if we support all methods in a class as intrinsic), we can reorder
-    // the checks to account for that.
+    // namespaceName, className, and methodName are all not null upfront.
 
     if ((namespaceName != nullptr) && (className != nullptr) && (methodName != nullptr))
     {

From 86e89137c9f82f692de71272f649f396fe745169 Mon Sep 17 00:00:00 2001
From: Tanner Gooding <tagoo@outlook.com>
Date: Thu, 21 Sep 2017 22:09:01 -0700
Subject: [PATCH 7/8] Adding back the case statement for
 CORINFO_INTRINSIC_Round, since it is required for Desktop compat.

---
 src/jit/importer.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index a101295ccd38..30969a134931 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -3346,6 +3346,7 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr            newobjThis,
         case CORINFO_INTRINSIC_Sqrt:
         case CORINFO_INTRINSIC_Abs:
         case CORINFO_INTRINSIC_Cos:
+        case CORINFO_INTRINSIC_Round:
         case CORINFO_INTRINSIC_Cosh:
         case CORINFO_INTRINSIC_Sinh:
         case CORINFO_INTRINSIC_Tan:

From eebceeb68d55590eab46c422a45d3f55edb2a123 Mon Sep 17 00:00:00 2001
From: Tanner Gooding <tagoo@outlook.com>
Date: Fri, 22 Sep 2017 17:52:16 -0700
Subject: [PATCH 8/8] Renaming the non-shared copy of Math.cs to
 Math.CoreCLR.cs

---
 src/mscorlib/System.Private.CoreLib.csproj           | 2 +-
 src/mscorlib/src/System/{Math.cs => Math.CoreCLR.cs} | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename src/mscorlib/src/System/{Math.cs => Math.CoreCLR.cs} (100%)

diff --git a/src/mscorlib/System.Private.CoreLib.csproj b/src/mscorlib/System.Private.CoreLib.csproj
index 90294fd527a7..557d744616da 100644
--- a/src/mscorlib/System.Private.CoreLib.csproj
+++ b/src/mscorlib/System.Private.CoreLib.csproj
@@ -329,7 +329,7 @@
     <Compile Include="$(BclSourcesRoot)\System\InsufficientMemoryException.cs" />
     <Compile Include="$(BclSourcesRoot)\System\IntPtr.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Internal.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Math.cs" />
+    <Compile Include="$(BclSourcesRoot)\System\Math.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\MathF.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\mda.cs" />
     <Compile Include="$(BclSourcesRoot)\System\MissingFieldException.cs" />
diff --git a/src/mscorlib/src/System/Math.cs b/src/mscorlib/src/System/Math.CoreCLR.cs
similarity index 100%
rename from src/mscorlib/src/System/Math.cs
rename to src/mscorlib/src/System/Math.CoreCLR.cs