Skip to content

Commit ac97f68

Browse files
authored
Improve min max performance and IEEE compliance (#2810)
***NO_CI***
1 parent 93438ee commit ac97f68

File tree

3 files changed

+172
-26
lines changed

3 files changed

+172
-26
lines changed

src/CLR/System.Math/nf_native_system_math.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ static const CLR_RT_MethodHandler method_lookup[] =
3131
Library_nf_native_system_math_System_Math::Log10___STATIC__R8__R8,
3232
NULL,
3333
Library_nf_native_system_math_System_Math::Max___STATIC__R8__R8__R8,
34-
NULL,
34+
Library_nf_native_system_math_System_Math::Max___STATIC__R4__R4__R4,
3535
NULL,
3636
Library_nf_native_system_math_System_Math::Min___STATIC__R8__R8__R8,
37-
NULL,
37+
Library_nf_native_system_math_System_Math::Min___STATIC__R4__R4__R4,
3838
Library_nf_native_system_math_System_Math::Pow___STATIC__R8__R8__R8,
3939
Library_nf_native_system_math_System_Math::Round___STATIC__R8__R8,
4040
Library_nf_native_system_math_System_Math::Sign___STATIC__I4__R8,
@@ -50,9 +50,9 @@ static const CLR_RT_MethodHandler method_lookup[] =
5050
const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_System_Math =
5151
{
5252
"System.Math",
53-
0x46092CB1,
53+
0x9F9E2A7E,
5454
method_lookup,
55-
{ 100, 0, 5, 4 }
55+
{ 100, 0, 5, 5 }
5656
};
5757

5858
// clang-format on

src/CLR/System.Math/nf_native_system_math.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ struct Library_nf_native_system_math_System_Math
2828
NANOCLR_NATIVE_DECLARE(Log___STATIC__R8__R8);
2929
NANOCLR_NATIVE_DECLARE(Log10___STATIC__R8__R8);
3030
NANOCLR_NATIVE_DECLARE(Max___STATIC__R8__R8__R8);
31+
NANOCLR_NATIVE_DECLARE(Max___STATIC__R4__R4__R4);
3132
NANOCLR_NATIVE_DECLARE(Min___STATIC__R8__R8__R8);
33+
NANOCLR_NATIVE_DECLARE(Min___STATIC__R4__R4__R4);
3234
NANOCLR_NATIVE_DECLARE(Pow___STATIC__R8__R8__R8);
3335
NANOCLR_NATIVE_DECLARE(Round___STATIC__R8__R8);
3436
NANOCLR_NATIVE_DECLARE(Sign___STATIC__I4__R8);

src/CLR/System.Math/nf_native_system_math_System_Math.cpp

Lines changed: 166 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,55 @@ HRESULT Library_nf_native_system_math_System_Math::Max___STATIC__R8__R8__R8(CLR_
1313
NATIVE_PROFILE_CLR_CORE();
1414
NANOCLR_HEADER();
1515

16+
// This matches the IEEE 754:2019 `maximum` function
17+
//
18+
// It propagates NaN inputs back to the caller and
19+
// otherwise returns the greater of the inputs. It
20+
// treats +0 as greater than -0 as per the specification.
21+
1622
#if (DP_FLOATINGPOINT == TRUE)
1723

18-
double x = stack.Arg0().NumericByRefConst().r8;
19-
double y = stack.Arg1().NumericByRefConst().r8;
24+
double val1 = stack.Arg0().NumericByRefConst().r8;
25+
double val2 = stack.Arg1().NumericByRefConst().r8;
2026

21-
// from .NET spec: If val1, val2, or both val1 and val2 are equal to NaN, NaN is returned.
22-
if (System::Double::IsNaN(x) || System::Double::IsNaN(y))
27+
if (val1 != val2)
2328
{
24-
stack.SetResult_R8(NAN);
29+
if (!__isnand(val1))
30+
{
31+
double res = val2 < val1 ? val1 : val2;
32+
stack.SetResult_R8(res);
33+
}
34+
else
35+
{
36+
stack.SetResult_R8(val1);
37+
}
2538
}
2639
else
2740
{
28-
double res = x >= y ? x : y;
29-
41+
double res = (__signbitd(val2) != 0) ? val1 : val2;
3042
stack.SetResult_R8(res);
3143
}
3244

3345
#else
3446

35-
float x = (float)stack.Arg0().NumericByRefConst().r8;
36-
float y = (float)stack.Arg1().NumericByRefConst().r8;
47+
float val1 = (float)stack.Arg0().NumericByRefConst().r8;
48+
float val2 = (float)stack.Arg1().NumericByRefConst().r8;
3749

38-
// from .NET spec: If val1, val2, or both val1 and val2 are equal to NaN, NaN is returned.
39-
if (System::Double::IsNaN(x) || System::Double::IsNaN(y))
50+
if (val1 != val2)
4051
{
41-
stack.SetResult_R8(NAN);
52+
if (!__isnand(val1))
53+
{
54+
float res = val2 < val1 ? val1 : val2;
55+
stack.SetResult_R8(res);
56+
}
57+
else
58+
{
59+
stack.SetResult_R8(val1);
60+
}
4261
}
4362
else
4463
{
45-
float res = x >= y ? x : y;
46-
64+
float res = (__signbitd(val2) != 0) ? val1 : val2;
4765
stack.SetResult_R8(res);
4866
}
4967

@@ -52,32 +70,138 @@ HRESULT Library_nf_native_system_math_System_Math::Max___STATIC__R8__R8__R8(CLR_
5270
NANOCLR_NOCLEANUP_NOLABEL();
5371
}
5472

73+
HRESULT Library_nf_native_system_math_System_Math::Max___STATIC__R4__R4__R4(CLR_RT_StackFrame &stack)
74+
{
75+
NATIVE_PROFILE_CLR_CORE();
76+
NANOCLR_HEADER();
77+
78+
// This matches the IEEE 754:2019 `maximum` function
79+
//
80+
// It propagates NaN inputs back to the caller and
81+
// otherwise returns the greater of the inputs. It
82+
// treats +0 as greater than -0 as per the specification.
83+
84+
float val1 = (float)stack.Arg0().NumericByRefConst().r4;
85+
float val2 = (float)stack.Arg1().NumericByRefConst().r4;
86+
87+
if (val1 != val2)
88+
{
89+
if (!__isnand(val1))
90+
{
91+
float res = val2 < val1 ? val1 : val2;
92+
stack.SetResult_R4(res);
93+
}
94+
else
95+
{
96+
stack.SetResult_R4(val1);
97+
}
98+
}
99+
else
100+
{
101+
float res = (__signbitd(val2) != 0) ? val1 : val2;
102+
stack.SetResult_R4(res);
103+
}
104+
105+
NANOCLR_NOCLEANUP_NOLABEL();
106+
}
107+
55108
HRESULT Library_nf_native_system_math_System_Math::Min___STATIC__R8__R8__R8(CLR_RT_StackFrame &stack)
56109
{
57110
NATIVE_PROFILE_CLR_CORE();
58111
NANOCLR_HEADER();
59112

113+
// This matches the IEEE 754:2019 `minimum` function
114+
//
115+
// It propagates NaN inputs back to the caller and
116+
// otherwise returns the lesser of the inputs. It
117+
// treats +0 as lesser than -0 as per the specification.
118+
60119
#if (DP_FLOATINGPOINT == TRUE)
61120

62-
double x = stack.Arg0().NumericByRefConst().r8;
63-
double y = stack.Arg1().NumericByRefConst().r8;
64-
double res = x <= y ? x : y;
121+
double val1 = stack.Arg0().NumericByRefConst().r8;
122+
double val2 = stack.Arg1().NumericByRefConst().r8;
65123

66-
stack.SetResult_R8(res);
124+
if (val1 != val2)
125+
{
126+
if (!__isnand(val1))
127+
{
128+
double res = val1 < val2 ? val1 : val2;
129+
stack.SetResult_R8(res);
130+
}
131+
else
132+
{
133+
stack.SetResult_R8(val1);
134+
}
135+
}
136+
else
137+
{
138+
double res = (__signbitd(val2) != 0) ? val1 : val2;
139+
stack.SetResult_R8(res);
140+
}
67141

68142
#else
69143

70-
float x = (float)stack.Arg0().NumericByRefConst().r8;
71-
float y = (float)stack.Arg1().NumericByRefConst().r8;
72-
float res = x <= y ? x : y;
144+
float val1 = (float)stack.Arg0().NumericByRefConst().r8;
145+
float val2 = (float)stack.Arg1().NumericByRefConst().r8;
73146

74-
stack.SetResult_R8(res);
147+
if (val1 != val2)
148+
{
149+
if (!__isnand(val1))
150+
{
151+
float res = val1 < val2 ? val1 : val2;
152+
stack.SetResult_R8(res);
153+
}
154+
else
155+
{
156+
stack.SetResult_R8((float)val1);
157+
}
158+
}
159+
else
160+
{
161+
float res = (__signbitd(val2) != 0) ? val1 : val2;
162+
stack.SetResult_R8(res);
163+
}
75164

76165
#endif
77166

78167
NANOCLR_NOCLEANUP_NOLABEL();
79168
}
80169

170+
HRESULT Library_nf_native_system_math_System_Math::Min___STATIC__R4__R4__R4(CLR_RT_StackFrame &stack)
171+
{
172+
NATIVE_PROFILE_CLR_CORE();
173+
NANOCLR_HEADER();
174+
175+
// This matches the IEEE 754:2019 `minimum` function
176+
//
177+
// It propagates NaN inputs back to the caller and
178+
// otherwise returns the lesser of the inputs. It
179+
// treats +0 as lesser than -0 as per the specification.
180+
181+
float val1 = (float)stack.Arg0().NumericByRefConst().r4;
182+
float val2 = (float)stack.Arg1().NumericByRefConst().r4;
183+
184+
if (val1 != val2)
185+
{
186+
if (!__isnand(val1))
187+
{
188+
float res = val1 < val2 ? val1 : val2;
189+
stack.SetResult_R4(res);
190+
}
191+
else
192+
{
193+
stack.SetResult_R4(val1);
194+
}
195+
}
196+
else
197+
{
198+
float res = (__signbitd(val2) != 0) ? val1 : val2;
199+
stack.SetResult_R8(res);
200+
}
201+
202+
NANOCLR_NOCLEANUP_NOLABEL();
203+
}
204+
81205
HRESULT Library_nf_native_system_math_System_Math::Abs___STATIC__R8__R8(CLR_RT_StackFrame &stack)
82206
{
83207
NATIVE_PROFILE_CLR_CORE();
@@ -820,6 +944,16 @@ HRESULT Library_nf_native_system_math_System_Math::Max___STATIC__R8__R8__R8(CLR_
820944
NANOCLR_NOCLEANUP();
821945
}
822946

947+
HRESULT Library_nf_native_system_math_System_Math::Max___STATIC__R4__R4__R4(CLR_RT_StackFrame &stack)
948+
{
949+
NATIVE_PROFILE_CLR_CORE();
950+
NANOCLR_HEADER();
951+
952+
NANOCLR_SET_AND_LEAVE(stack.NotImplementedStub());
953+
954+
NANOCLR_NOCLEANUP();
955+
}
956+
823957
HRESULT Library_nf_native_system_math_System_Math::Min___STATIC__R8__R8__R8(CLR_RT_StackFrame &stack)
824958
{
825959
NATIVE_PROFILE_CLR_CORE();
@@ -830,6 +964,16 @@ HRESULT Library_nf_native_system_math_System_Math::Min___STATIC__R8__R8__R8(CLR_
830964
NANOCLR_NOCLEANUP();
831965
}
832966

967+
HRESULT Library_nf_native_system_math_System_Math::Min___STATIC__R4__R4__R4(CLR_RT_StackFrame &stack)
968+
{
969+
NATIVE_PROFILE_CLR_CORE();
970+
NANOCLR_HEADER();
971+
972+
NANOCLR_SET_AND_LEAVE(stack.NotImplementedStub());
973+
974+
NANOCLR_NOCLEANUP();
975+
}
976+
833977
HRESULT Library_nf_native_system_math_System_Math::Abs___STATIC__R8__R8(CLR_RT_StackFrame &stack)
834978
{
835979
NATIVE_PROFILE_CLR_CORE();

0 commit comments

Comments
 (0)