Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better codegen / perf form Math.Max and Math.Min #33851

Merged
merged 5 commits into from
Apr 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 24 additions & 30 deletions src/libraries/System.Private.CoreLib/src/System/Math.cs
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ public static decimal Max(decimal val1, decimal val2)
return decimal.Max(val1, val2);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Max(double val1, double val2)
{
// This matches the IEEE 754:2019 `maximum` function
Expand All @@ -547,17 +548,17 @@ public static double Max(double val1, double val2)
// otherwise returns the larger of the inputs. It
// treats +0 as larger than -0 as per the specification.

if ((val1 > val2) || double.IsNaN(val1))
if (val1 != val2)
{
return val1;
}
if (!double.IsNaN(val1))
{
return val2 < val1 ? val1 : val2;
}

if (val1 == val2)
{
return double.IsNegative(val1) ? val2 : val1;
return val1;
}

return val2;
return double.IsNegative(val2) ? val1 : val2;
}

[NonVersionable]
Expand Down Expand Up @@ -585,6 +586,7 @@ public static sbyte Max(sbyte val1, sbyte val2)
return (val1 >= val2) ? val1 : val2;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Max(float val1, float val2)
{
// This matches the IEEE 754:2019 `maximum` function
Expand All @@ -593,17 +595,17 @@ public static float Max(float val1, float val2)
// otherwise returns the larger of the inputs. It
// treats +0 as larger than -0 as per the specification.

if ((val1 > val2) || float.IsNaN(val1))
if (val1 != val2)
{
return val1;
}
if (!float.IsNaN(val1))
{
return val2 < val1 ? val1 : val2;
}

if (val1 == val2)
{
return float.IsNegative(val1) ? val2 : val1;
return val1;
}

return val2;
return float.IsNegative(val2) ? val1 : val2;
}

[CLSCompliant(false)]
Expand Down Expand Up @@ -663,6 +665,7 @@ public static decimal Min(decimal val1, decimal val2)
return decimal.Min(val1, val2);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Min(double val1, double val2)
{
// This matches the IEEE 754:2019 `minimum` function
Expand All @@ -671,17 +674,12 @@ public static double Min(double val1, double val2)
// otherwise returns the larger of the inputs. It
// treats +0 as larger than -0 as per the specification.

if ((val1 < val2) || double.IsNaN(val1))
{
return val1;
}

if (val1 == val2)
if (val1 != val2 && !double.IsNaN(val1))
{
return double.IsNegative(val1) ? val1 : val2;
return val1 < val2 ? val1 : val2;
}

return val2;
return double.IsNegative(val1) ? val1 : val2;
}

[NonVersionable]
Expand Down Expand Up @@ -709,6 +707,7 @@ public static sbyte Min(sbyte val1, sbyte val2)
return (val1 <= val2) ? val1 : val2;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Min(float val1, float val2)
{
// This matches the IEEE 754:2019 `minimum` function
Expand All @@ -717,17 +716,12 @@ public static float Min(float val1, float val2)
// otherwise returns the larger of the inputs. It
// treats +0 as larger than -0 as per the specification.

if ((val1 < val2) || float.IsNaN(val1))
{
return val1;
}

if (val1 == val2)
if (val1 != val2 && !float.IsNaN(val1))
{
return float.IsNegative(val1) ? val1 : val2;
return val1 < val2 ? val1 : val2;
}

return val2;
return float.IsNegative(val1) ? val1 : val2;
}

[CLSCompliant(false)]
Expand Down
88 changes: 64 additions & 24 deletions src/libraries/System.Runtime.Extensions/tests/System/Math.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,12 +1052,22 @@ public static void Max_Decimal()

[Theory]
[InlineData(double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity)]
[InlineData(double.MinValue, double.MaxValue, double.MaxValue)]
[InlineData(double.NaN, double.NaN, double.NaN)]
[InlineData(-0.0, 0.0, 0.0)]
[InlineData(2.0, -3.0, 2.0)]
[InlineData(3.0, -2.0, 3.0)]
[InlineData(double.PositiveInfinity, double.NaN, double.NaN)]
[InlineData(double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity)]
[InlineData(double.MinValue, double.MaxValue, double.MaxValue)]
[InlineData(double.MaxValue, double.MinValue, double.MaxValue)]
[InlineData(double.NaN, double.NaN, double.NaN)]
[InlineData(double.NaN, 1.0, double.NaN)]
[InlineData(1.0, double.NaN, double.NaN)]
[InlineData(double.PositiveInfinity, double.NaN, double.NaN)]
[InlineData(double.NegativeInfinity, double.NaN, double.NaN)]
[InlineData(double.NaN, double.PositiveInfinity, double.NaN)]
[InlineData(double.NaN, double.NegativeInfinity, double.NaN)]
[InlineData(-0.0, 0.0, 0.0)]
[InlineData( 0.0, -0.0, 0.0)]
[InlineData( 2.0, -3.0, 2.0)]
[InlineData(-3.0, 2.0, 2.0)]
[InlineData( 3.0, -2.0, 3.0)]
[InlineData(-2.0, 3.0, 3.0)]
public static void Max_Double_NotNetFramework(double x, double y, double expectedResult)
{
AssertEqual(expectedResult, Math.Max(x, y), 0.0);
Expand Down Expand Up @@ -1093,12 +1103,22 @@ public static void Max_SByte()

[Theory]
[InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)]
[InlineData(float.MinValue, float.MaxValue, float.MaxValue)]
[InlineData(float.NaN, float.NaN, float.NaN)]
[InlineData(-0.0f, 0.0f, 0.0f)]
[InlineData(2.0f, -3.0f, 2.0f)]
[InlineData(3.0f, -2.0f, 3.0f)]
[InlineData(float.PositiveInfinity, float.NaN, float.NaN)]
[InlineData(float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity)]
[InlineData(float.MinValue, float.MaxValue, float.MaxValue)]
[InlineData(float.MaxValue, float.MinValue, float.MaxValue)]
[InlineData(float.NaN, float.NaN, float.NaN)]
[InlineData(float.NaN, 1.0, float.NaN)]
[InlineData(1.0, float.NaN, float.NaN)]
[InlineData(float.PositiveInfinity, float.NaN, float.NaN)]
[InlineData(float.NegativeInfinity, float.NaN, float.NaN)]
[InlineData(float.NaN, float.PositiveInfinity, float.NaN)]
[InlineData(float.NaN, float.NegativeInfinity, float.NaN)]
[InlineData(-0.0, 0.0, 0.0)]
[InlineData( 0.0, -0.0, 0.0)]
[InlineData( 2.0, -3.0, 2.0)]
[InlineData(-3.0, 2.0, 2.0)]
[InlineData( 3.0, -2.0, 3.0)]
[InlineData(-2.0, 3.0, 3.0)]
public static void Max_Single_NotNetFramework(float x, float y, float expectedResult)
{
AssertEqual(expectedResult, Math.Max(x, y), 0.0f);
Expand Down Expand Up @@ -1141,12 +1161,22 @@ public static void Min_Decimal()

[Theory]
[InlineData(double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity)]
[InlineData(double.MinValue, double.MaxValue, double.MinValue)]
[InlineData(double.NaN, double.NaN, double.NaN)]
[InlineData(-0.0, 0.0, -0.0)]
[InlineData(2.0, -3.0, -3.0)]
[InlineData(3.0, -2.0, -2.0)]
[InlineData(double.PositiveInfinity, double.NaN, double.NaN)]
[InlineData(double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity)]
[InlineData(double.MinValue, double.MaxValue, double.MinValue)]
[InlineData(double.MaxValue, double.MinValue, double.MinValue)]
[InlineData(double.NaN, double.NaN, double.NaN)]
[InlineData(double.NaN, 1.0, double.NaN)]
[InlineData(1.0, double.NaN, double.NaN)]
[InlineData(double.PositiveInfinity, double.NaN, double.NaN)]
[InlineData(double.NegativeInfinity, double.NaN, double.NaN)]
[InlineData(double.NaN, double.PositiveInfinity, double.NaN)]
[InlineData(double.NaN, double.NegativeInfinity, double.NaN)]
[InlineData(-0.0, 0.0, -0.0)]
[InlineData( 0.0, -0.0, -0.0)]
[InlineData( 2.0, -3.0, -3.0)]
[InlineData(-3.0, 2.0, -3.0)]
[InlineData( 3.0, -2.0, -2.0)]
[InlineData(-2.0, 3.0, -2.0)]
public static void Min_Double_NotNetFramework(double x, double y, double expectedResult)
{
AssertEqual(expectedResult, Math.Min(x, y), 0.0);
Expand Down Expand Up @@ -1182,12 +1212,22 @@ public static void Min_SByte()

[Theory]
[InlineData(float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)]
[InlineData(float.MinValue, float.MaxValue, float.MinValue)]
[InlineData(float.NaN, float.NaN, float.NaN)]
[InlineData(-0.0f, 0.0f, -0.0f)]
[InlineData(2.0f, -3.0f, -3.0f)]
[InlineData(3.0f, -2.0f, -2.0f)]
[InlineData(float.PositiveInfinity, float.NaN, float.NaN)]
[InlineData(float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity)]
[InlineData(float.MinValue, float.MaxValue, float.MinValue)]
[InlineData(float.MaxValue, float.MinValue, float.MinValue)]
[InlineData(float.NaN, float.NaN, float.NaN)]
[InlineData(float.NaN, 1.0, float.NaN)]
[InlineData(1.0, float.NaN, float.NaN)]
[InlineData(float.PositiveInfinity, float.NaN, float.NaN)]
[InlineData(float.NegativeInfinity, float.NaN, float.NaN)]
[InlineData(float.NaN, float.PositiveInfinity, float.NaN)]
[InlineData(float.NaN, float.NegativeInfinity, float.NaN)]
[InlineData(-0.0, 0.0, -0.0)]
[InlineData( 0.0, -0.0, -0.0)]
[InlineData( 2.0, -3.0, -3.0)]
[InlineData(-3.0, 2.0, -3.0)]
[InlineData( 3.0, -2.0, -2.0)]
[InlineData(-2.0, 3.0, -2.0)]
public static void Min_Single_NotNetFramework(float x, float y, float expectedResult)
{
AssertEqual(expectedResult, Math.Min(x, y), 0.0f);
Expand Down