Skip to content

Commit 77af230

Browse files
committed
Saturating floating point to integer conversions on Arm32
Follow up on dotnet#97529 (comment)
1 parent f91b911 commit 77af230

File tree

4 files changed

+5
-102
lines changed

4 files changed

+5
-102
lines changed

src/coreclr/nativeaot/Runtime/MathHelpers.cpp

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,7 @@ FCIMPL1_D(uint64_t, RhpDbl2ULng, double val)
1515
const double uint64_max_plus_1 = 4294967296.0 * 4294967296.0;
1616
return (val > 0) ? ((val >= uint64_max_plus_1) ? UINT64_MAX : (uint64_t)val) : 0;
1717
#else
18-
const double two63 = 2147483648.0 * 4294967296.0;
19-
uint64_t ret;
20-
if (val < two63)
21-
{
22-
ret = (int64_t)(val);
23-
}
24-
else
25-
{
26-
// subtract 0x8000000000000000, do the convert then add it back again
27-
ret = (int64_t)(val - two63) + I64(0x8000000000000000);
28-
}
29-
return ret;
18+
return (uint64_t)val;
3019
#endif //HOST_X86 || HOST_AMD64
3120
}
3221
FCIMPLEND
@@ -358,4 +347,4 @@ FCIMPL2_FI(float, modff, float x, float* intptr)
358347
return std::modff(x, intptr);
359348
FCIMPLEND
360349

361-
#endif
350+
#endif

src/coreclr/vm/jithelpers.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -625,16 +625,7 @@ HCIMPL1_V(UINT64, JIT_Dbl2ULng, double val)
625625
return (val >= 0) ? ((val >= uint64_max_plus_1) ? UINT64_MAX : (UINT64)val) : 0;
626626

627627
#else
628-
const double two63 = 2147483648.0 * 4294967296.0;
629-
UINT64 ret;
630-
if (val < two63) {
631-
ret = (INT64)(val);
632-
}
633-
else {
634-
// subtract 0x8000000000000000, do the convert then add it back again
635-
ret = (INT64)(val - two63) + I64(0x8000000000000000);
636-
}
637-
return ret;
628+
return((UINT64)val);
638629
#endif // TARGET_X86 || TARGET_AMD64
639630
}
640631
HCIMPLEND

src/tests/JIT/Directed/Convert/out_of_range_fp_to_int_conversions.cpp

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ typedef enum {
1717
CONVERT_SENTINEL,
1818
CONVERT_SATURATING,
1919
CONVERT_NATIVECOMPILERBEHAVIOR,
20-
CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32,
2120
} FPtoIntegerConversionType;
2221

2322
extern "C" DLLEXPORT int32_t ConvertDoubleToInt32(double x, FPtoIntegerConversionType t)
@@ -32,7 +31,6 @@ extern "C" DLLEXPORT int32_t ConvertDoubleToInt32(double x, FPtoIntegerConversio
3231
case CONVERT_SENTINEL:
3332
return ((x != x) || (x < INT32_MIN) || (x > INT32_MAX)) ? INT32_MIN : (int32_t)x;
3433

35-
case CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32:
3634
case CONVERT_SATURATING:
3735
return (x != x) ? 0 : (x < INT32_MIN) ? INT32_MIN : (x > INT32_MAX) ? INT32_MAX : (int32_t)x;
3836
case CONVERT_NATIVECOMPILERBEHAVIOR: // handled above, but add case to silence warning
@@ -57,7 +55,6 @@ extern "C" DLLEXPORT uint32_t ConvertDoubleToUInt32(double x, FPtoIntegerConvers
5755
case CONVERT_SENTINEL:
5856
return ((x != x) || (x < 0) || (x > UINT32_MAX)) ? UINT32_MAX : (uint32_t)x;
5957

60-
case CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32:
6158
case CONVERT_SATURATING:
6259
return ((x != x) || (x < 0)) ? 0 : (x > UINT32_MAX) ? UINT32_MAX : (uint32_t)x;
6360
case CONVERT_NATIVECOMPILERBEHAVIOR: // handled above, but add case to silence warning
@@ -67,14 +64,6 @@ extern "C" DLLEXPORT uint32_t ConvertDoubleToUInt32(double x, FPtoIntegerConvers
6764
return 0;
6865
}
6966

70-
static uint64_t CppNativeArm32ConvertDoubleToUInt64(double y)
71-
{
72-
const double uintmax_plus_1 = -2.0 * (double)INT32_MIN;
73-
uint32_t hi32Bits = ConvertDoubleToUInt32(y / uintmax_plus_1, CONVERT_SATURATING);
74-
uint32_t lo32Bits = ConvertDoubleToUInt32(y - (((double)hi32Bits) * uintmax_plus_1), CONVERT_SATURATING);
75-
return (((uint64_t)hi32Bits) << 32) + lo32Bits;
76-
}
77-
7867
extern "C" DLLEXPORT int64_t ConvertDoubleToInt64(double x, FPtoIntegerConversionType t)
7968
{
8069
if (t == CONVERT_NATIVECOMPILERBEHAVIOR)
@@ -96,16 +85,6 @@ extern "C" DLLEXPORT int64_t ConvertDoubleToInt64(double x, FPtoIntegerConversio
9685
case CONVERT_SENTINEL:
9786
return ((x != x) || (x < INT64_MIN) || (x >= int64_max_plus_1)) ? INT64_MIN : (int64_t)x;
9887

99-
case CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32:
100-
if (x > 0)
101-
{
102-
return (int64_t)CppNativeArm32ConvertDoubleToUInt64(x);
103-
}
104-
else
105-
{
106-
return -(int64_t)CppNativeArm32ConvertDoubleToUInt64(-x);
107-
}
108-
10988
case CONVERT_SATURATING:
11089
return (x != x) ? 0 : (x < INT64_MIN) ? INT64_MIN : (x >= int64_max_plus_1) ? INT64_MAX : (int64_t)x;
11190
case CONVERT_NATIVECOMPILERBEHAVIOR: // handled above, but add case to silence warning
@@ -138,18 +117,6 @@ extern "C" DLLEXPORT uint64_t ConvertDoubleToUInt64(double x, FPtoIntegerConver
138117
case CONVERT_SATURATING:
139118
return ((x != x) || (x < 0)) ? 0 : (x >= uint64_max_plus_1) ? UINT64_MAX : (uint64_t)x;
140119

141-
case CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32:
142-
{
143-
if (x < int64_max_plus_1)
144-
{
145-
return (uint64_t)ConvertDoubleToInt64(x, CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32);
146-
}
147-
else
148-
{
149-
return (uint64_t)ConvertDoubleToInt64(x - int64_max_plus_1, CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32) + (0x8000000000000000);
150-
}
151-
}
152-
153120
case CONVERT_NATIVECOMPILERBEHAVIOR: // handled above, but add case to silence warning
154121
return 0;
155122
}

src/tests/JIT/Directed/Convert/out_of_range_fp_to_int_conversions.cs

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public enum FPtoIntegerConversionType
1919
CONVERT_SENTINEL,
2020
CONVERT_SATURATING,
2121
CONVERT_NATIVECOMPILERBEHAVIOR,
22-
CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32,
2322
}
2423

2524
public enum ConversionType
@@ -91,7 +90,6 @@ public static int ConvertDoubleToInt32(double x, FPtoIntegerConversionType t)
9190
return (Double.IsNaN(x) || (x<int.MinValue) || (x > int.MaxValue)) ? int.MinValue: (int) x;
9291

9392
case FPtoIntegerConversionType.CONVERT_SATURATING:
94-
case FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32:
9593
return Double.IsNaN(x) ? 0 : (x< int.MinValue) ? int.MinValue : (x > int.MaxValue) ? int.MaxValue : (int) x;
9694
}
9795
return 0;
@@ -114,7 +112,6 @@ public static uint ConvertDoubleToUInt32(double x, FPtoIntegerConversionType t)
114112
return (Double.IsNaN(x) || (x < 0) || (x > uint.MaxValue)) ? uint.MaxValue : (uint)x;
115113

116114
case FPtoIntegerConversionType.CONVERT_SATURATING:
117-
case FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32:
118115
return (Double.IsNaN(x) || (x < 0)) ? 0 : (x > uint.MaxValue) ? uint.MaxValue : (uint)x;
119116
}
120117

@@ -137,29 +134,11 @@ public static long ConvertDoubleToInt64(double x, FPtoIntegerConversionType t)
137134
case FPtoIntegerConversionType.CONVERT_SENTINEL:
138135
return (Double.IsNaN(x) || (x < long.MinValue) || (x >= llong_max_plus_1)) ? long.MinValue : (long)x;
139136

140-
case FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32:
141-
if (x > 0)
142-
{
143-
return (long)CppNativeArm32ConvertDoubleToUInt64(x);
144-
}
145-
else
146-
{
147-
return -(long)CppNativeArm32ConvertDoubleToUInt64(-x);
148-
}
149-
150137
case FPtoIntegerConversionType.CONVERT_SATURATING:
151138
return Double.IsNaN(x) ? 0 : (x < long.MinValue) ? long.MinValue : (x >= llong_max_plus_1) ? long.MaxValue : (long)x;
152139
}
153140

154141
return 0;
155-
156-
static ulong CppNativeArm32ConvertDoubleToUInt64(double y)
157-
{
158-
const double uintmax_plus_1 = -2.0 * (double)int.MinValue;
159-
uint hi32Bits = ConvertDoubleToUInt32(y / uintmax_plus_1, FPtoIntegerConversionType.CONVERT_SATURATING);
160-
uint lo32Bits = ConvertDoubleToUInt32(y - (((double)hi32Bits) * uintmax_plus_1), FPtoIntegerConversionType.CONVERT_SATURATING);
161-
return (((ulong)hi32Bits) << (int)32) + lo32Bits;
162-
}
163142
}
164143

165144
public static ulong ConvertDoubleToUInt64(double x, FPtoIntegerConversionType t)
@@ -183,18 +162,6 @@ public static ulong ConvertDoubleToUInt64(double x, FPtoIntegerConversionType t)
183162

184163
case FPtoIntegerConversionType.CONVERT_SATURATING:
185164
return (Double.IsNaN(x) || (x < 0)) ? 0 : (x >= ullong_max_plus_1) ? ulong.MaxValue : (ulong)x;
186-
187-
case FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32:
188-
{
189-
if (x < two63)
190-
{
191-
return (ulong)ConvertDoubleToInt64(x, FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32);
192-
}
193-
else
194-
{
195-
return (ulong)ConvertDoubleToInt64(x - two63, FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32) + (0x8000000000000000);
196-
}
197-
}
198165
}
199166

200167
return 0;
@@ -261,7 +228,6 @@ static void TestBitValue(uint value, double? dblValNullable = null, FPtoIntegerC
261228

262229
if (!tValue.HasValue)
263230
{
264-
TestBitValue(value, dblVal, FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32);
265231
TestBitValue(value, dblVal, FPtoIntegerConversionType.CONVERT_BACKWARD_COMPATIBLE);
266232
TestBitValue(value, dblVal, FPtoIntegerConversionType.CONVERT_SATURATING);
267233
TestBitValue(value, dblVal, FPtoIntegerConversionType.CONVERT_SENTINEL);
@@ -355,18 +321,8 @@ static void TestBitValue(uint value, double? dblValNullable = null, FPtoIntegerC
355321
[Fact]
356322
public static int TestEntryPoint()
357323
{
358-
switch (RuntimeInformation.ProcessArchitecture)
359-
{
360-
case Architecture.Arm:
361-
Program.ManagedConversionRule = FPtoIntegerConversionType.CONVERT_MANAGED_BACKWARD_COMPATIBLE_ARM32;
362-
break;
363-
364-
case Architecture.X86:
365-
case Architecture.X64:
366-
case Architecture.Arm64:
367-
Program.ManagedConversionRule = FPtoIntegerConversionType.CONVERT_SATURATING;
368-
break;
369-
}
324+
Program.ManagedConversionRule = FPtoIntegerConversionType.CONVERT_SATURATING;
325+
370326
Console.WriteLine($"Expected managed float behavior is {Program.ManagedConversionRule} Execute with parameter to adjust");
371327
Console.WriteLine("Specific test cases");
372328

0 commit comments

Comments
 (0)