Skip to content

Commit 988cfcf

Browse files
authored
Saturating floating point to integer conversions on Arm32 (#100682)
* Saturating floating point to integer conversions on Arm32 Follow up on #97529 (comment) * Fixes, cleanup
1 parent 7c4fc07 commit 988cfcf

File tree

4 files changed

+37
-142
lines changed

4 files changed

+37
-142
lines changed

src/coreclr/nativeaot/Runtime/MathHelpers.cpp

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,20 @@ 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;
30-
#endif //HOST_X86 || HOST_AMD64
18+
return (uint64_t)val;
19+
#endif
3120
}
3221
FCIMPLEND
3322

3423
FCIMPL1_D(int64_t, RhpDbl2Lng, double val)
3524
{
36-
#if defined(HOST_X86) || defined(HOST_AMD64)
25+
#if defined(HOST_X86) || defined(HOST_AMD64) || defined(HOST_ARM)
3726
const double int64_min = -2147483648.0 * 4294967296.0;
3827
const double int64_max = 2147483648.0 * 4294967296.0;
3928
return (val != val) ? 0 : (val <= int64_min) ? INT64_MIN : (val >= int64_max) ? INT64_MAX : (int64_t)val;
4029
#else
4130
return (int64_t)val;
42-
#endif //HOST_X86 || HOST_AMD64
31+
#endif
4332
}
4433
FCIMPLEND
4534

@@ -51,7 +40,7 @@ FCIMPL1_D(int32_t, RhpDbl2Int, double val)
5140
return (val != val) ? 0 : (val <= int32_min) ? INT32_MIN : (val >= int32_max_plus_1) ? INT32_MAX : (int32_t)val;
5241
#else
5342
return (int32_t)val;
54-
#endif //HOST_X86 || HOST_AMD64
43+
#endif
5544
}
5645
FCIMPLEND
5746

@@ -62,7 +51,7 @@ FCIMPL1_D(uint32_t, RhpDbl2UInt, double val)
6251
return (val > 0) ? ((val >= uint_max) ? UINT32_MAX : (uint32_t)val) : 0;
6352
#else
6453
return (uint32_t)val;
65-
#endif //HOST_X86 || HOST_AMD64
54+
#endif
6655
}
6756
FCIMPLEND
6857

@@ -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: 28 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -491,51 +491,44 @@ HCIMPLEND
491491
#include <optsmallperfcritical.h>
492492

493493
/*********************************************************************/
494-
//
495-
HCIMPL1_V(double, JIT_ULng2Dbl, UINT64 val)
494+
HCIMPL1_V(double, JIT_ULng2Dbl, uint64_t val)
496495
{
497496
FCALL_CONTRACT;
498-
499-
double conv = (double) ((INT64) val);
500-
if (conv < 0)
501-
conv += (4294967296.0 * 4294967296.0); // add 2^64
502-
_ASSERTE(conv >= 0);
503-
return(conv);
497+
return (double)val;
504498
}
505499
HCIMPLEND
506500

507501
/*********************************************************************/
508-
// needed for ARM and RyuJIT-x86
509-
HCIMPL1_V(double, JIT_Lng2Dbl, INT64 val)
502+
HCIMPL1_V(double, JIT_Lng2Dbl, int64_t val)
510503
{
511504
FCALL_CONTRACT;
512-
return double(val);
505+
return (double)val;
513506
}
514507
HCIMPLEND
515508

516509
/*********************************************************************/
517-
HCIMPL1_V(INT64, JIT_Dbl2Lng, double val)
510+
HCIMPL1_V(int64_t, JIT_Dbl2Lng, double val)
518511
{
519512
FCALL_CONTRACT;
520513

521-
#if defined(TARGET_X86) || defined(TARGET_AMD64)
514+
#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM)
522515
const double int64_min = -2147483648.0 * 4294967296.0;
523516
const double int64_max = 2147483648.0 * 4294967296.0;
524-
return (val != val) ? 0 : (val <= int64_min) ? INT64_MIN : (val >= int64_max) ? INT64_MAX : (INT64)val;
517+
return (val != val) ? 0 : (val <= int64_min) ? INT64_MIN : (val >= int64_max) ? INT64_MAX : (int64_t)val;
525518
#else
526-
return((INT64)val);
527-
#endif // TARGET_X86 || TARGET_AMD64
519+
return (int64_t)val;
520+
#endif
528521
}
529522
HCIMPLEND
530523

531524
/*********************************************************************/
532-
HCIMPL1_V(UINT32, JIT_Dbl2UIntOvf, double val)
525+
HCIMPL1_V(uint32_t, JIT_Dbl2UIntOvf, double val)
533526
{
534527
FCALL_CONTRACT;
535528

536529
// Note that this expression also works properly for val = NaN case
537530
if (val > -1.0 && val < 4294967296.0)
538-
return((UINT32)val);
531+
return (uint32_t)val;
539532

540533
FCThrow(kOverflowException);
541534
}
@@ -549,14 +542,14 @@ HCIMPL1_V(int, JIT_Dbl2IntOvf, double val)
549542
const double two31 = 2147483648.0;
550543
// Note that this expression also works properly for val = NaN case
551544
if (val > -two31 - 1 && val < two31)
552-
return((INT32)val);
545+
return (int32_t)val;
553546

554547
FCThrow(kOverflowException);
555548
}
556549
HCIMPLEND
557550

558551
/*********************************************************************/
559-
HCIMPL1_V(INT64, JIT_Dbl2LngOvf, double val)
552+
HCIMPL1_V(int64_t, JIT_Dbl2LngOvf, double val)
560553
{
561554
FCALL_CONTRACT;
562555

@@ -565,77 +558,67 @@ HCIMPL1_V(INT64, JIT_Dbl2LngOvf, double val)
565558
// Note that this expression also works properly for val = NaN case
566559
// We need to compare with the very next double to two63. 0x402 is epsilon to get us there.
567560
if (val > -two63 - 0x402 && val < two63)
568-
return((INT64)val);
561+
return (int64_t)val;
569562

570563
FCThrow(kOverflowException);
571564
}
572565
HCIMPLEND
573566

574567
/*********************************************************************/
575-
HCIMPL1_V(UINT64, JIT_Dbl2ULngOvf, double val)
568+
HCIMPL1_V(uint64_t, JIT_Dbl2ULngOvf, double val)
576569
{
577570
FCALL_CONTRACT;
578571

579572
const double two64 = 4294967296.0 * 4294967296.0;
580573
// Note that this expression also works properly for val = NaN case
581574
if (val > -1.0 && val < two64)
582-
return (UINT64)val;
575+
return (uint64_t)val;
583576

584577
FCThrow(kOverflowException);
585578
}
586579
HCIMPLEND
587580

588-
HCIMPL1_V(UINT32, JIT_Dbl2UInt, double val)
581+
HCIMPL1_V(uint32_t, JIT_Dbl2UInt, double val)
589582
{
590583
FCALL_CONTRACT;
591584

592585
#if defined(TARGET_X86) || defined(TARGET_AMD64)
593586
const double uint_max = 4294967295.0;
594587
// Note that this expression also works properly for val = NaN case
595-
return (val >= 0) ? ((val >= uint_max) ? UINT32_MAX : (UINT32)val) : 0;
588+
return (val >= 0) ? ((val >= uint_max) ? UINT32_MAX : (uint32_t)val) : 0;
596589
#else
597-
return((UINT32)val);
598-
#endif //TARGET_X86 || TARGET_AMD64
590+
return (uint32_t)val;
591+
#endif
599592
}
600593
HCIMPLEND
601594

602595
/*********************************************************************/
603-
HCIMPL1_V(INT32, JIT_Dbl2Int, double val)
596+
HCIMPL1_V(int32_t, JIT_Dbl2Int, double val)
604597
{
605598
FCALL_CONTRACT;
606599

607600
#if defined(TARGET_X86) || defined(TARGET_AMD64)
608601
const double int32_min = -2147483648.0;
609602
const double int32_max_plus_1 = 2147483648.0;
610-
return (val != val) ? 0 : (val <= int32_min) ? INT32_MIN : (val >= int32_max_plus_1) ? INT32_MAX : (INT32)val;
603+
return (val != val) ? 0 : (val <= int32_min) ? INT32_MIN : (val >= int32_max_plus_1) ? INT32_MAX : (int32_t)val;
611604
#else
612-
return((INT32)val);
613-
#endif // TARGET_X86 || TARGET_AMD64
605+
return (int32_t)val;
606+
#endif
614607
}
615608
HCIMPLEND
616609

617610
/*********************************************************************/
618-
HCIMPL1_V(UINT64, JIT_Dbl2ULng, double val)
611+
HCIMPL1_V(uint64_t, JIT_Dbl2ULng, double val)
619612
{
620613
FCALL_CONTRACT;
621614

622615
#if defined(TARGET_X86) || defined(TARGET_AMD64)
623616
const double uint64_max_plus_1 = 4294967296.0 * 4294967296.0;
624617
// Note that this expression also works properly for val = NaN case
625-
return (val >= 0) ? ((val >= uint64_max_plus_1) ? UINT64_MAX : (UINT64)val) : 0;
626-
618+
return (val >= 0) ? ((val >= uint64_max_plus_1) ? UINT64_MAX : (uint64_t)val) : 0;
627619
#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;
638-
#endif // TARGET_X86 || TARGET_AMD64
620+
return (uint64_t)val;
621+
#endif
639622
}
640623
HCIMPLEND
641624

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
}

0 commit comments

Comments
 (0)