Skip to content

Commit 1ade285

Browse files
authored
Use Unsafe.BitCast for Interlocked.{Compare}Exchange of float/double (#87166)
* Update {Compare}Exchange in coreclr to use Unsafe.As * Remove corresponding FCalls * Share with mono * Remove Mono icalls * Add AggressiveInlining * Remove unused union type in mono
1 parent 1a1b1f8 commit 1ade285

File tree

10 files changed

+38
-235
lines changed

10 files changed

+38
-235
lines changed

src/coreclr/System.Private.CoreLib/src/System/Threading/Interlocked.CoreCLR.cs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,6 @@ public static long Decrement(ref long location) =>
6060
[MethodImpl(MethodImplOptions.InternalCall)]
6161
public static extern long Exchange(ref long location1, long value);
6262

63-
/// <summary>Sets a single-precision floating point number to a specified value and returns the original value, as an atomic operation.</summary>
64-
/// <param name="location1">The variable to set to the specified value.</param>
65-
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
66-
/// <returns>The original value of <paramref name="location1"/>.</returns>
67-
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
68-
[MethodImpl(MethodImplOptions.InternalCall)]
69-
public static extern float Exchange(ref float location1, float value);
70-
71-
/// <summary>Sets a double-precision floating point number to a specified value and returns the original value, as an atomic operation.</summary>
72-
/// <param name="location1">The variable to set to the specified value.</param>
73-
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
74-
/// <returns>The original value of <paramref name="location1"/>.</returns>
75-
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
76-
[MethodImpl(MethodImplOptions.InternalCall)]
77-
public static extern double Exchange(ref double location1, double value);
78-
7963
/// <summary>Sets an object to the specified value and returns a reference to the original object, as an atomic operation.</summary>
8064
/// <param name="location1">The variable to set to the specified value.</param>
8165
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
@@ -122,24 +106,6 @@ public static T Exchange<T>([NotNullIfNotNull(nameof(value))] ref T location1, T
122106
[MethodImpl(MethodImplOptions.InternalCall)]
123107
public static extern long CompareExchange(ref long location1, long value, long comparand);
124108

125-
/// <summary>Compares two single-precision floating point numbers for equality and, if they are equal, replaces the first value.</summary>
126-
/// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
127-
/// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
128-
/// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
129-
/// <returns>The original value in <paramref name="location1"/>.</returns>
130-
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
131-
[MethodImpl(MethodImplOptions.InternalCall)]
132-
public static extern float CompareExchange(ref float location1, float value, float comparand);
133-
134-
/// <summary>Compares two double-precision floating point numbers for equality and, if they are equal, replaces the first value.</summary>
135-
/// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
136-
/// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
137-
/// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
138-
/// <returns>The original value in <paramref name="location1"/>.</returns>
139-
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
140-
[MethodImpl(MethodImplOptions.InternalCall)]
141-
public static extern double CompareExchange(ref double location1, double value, double comparand);
142-
143109
/// <summary>Compares two objects for reference equality and, if they are equal, replaces the first object.</summary>
144110
/// <param name="location1">The destination object that is compared by reference with <paramref name="comparand"/> and possibly replaced.</param>
145111
/// <param name="value">The object that replaces the destination object if the reference comparison results in equality.</param>

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Interlocked.cs

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
using System.Runtime;
55
using System.Runtime.CompilerServices;
66
using System.Diagnostics.CodeAnalysis;
7-
using System.Runtime.Versioning;
8-
9-
using Internal.Runtime.CompilerServices;
107

118
namespace System.Threading
129
{
@@ -26,22 +23,6 @@ public static long CompareExchange(ref long location1, long value, long comparan
2623
return RuntimeImports.InterlockedCompareExchange(ref location1, value, comparand);
2724
}
2825

29-
[Intrinsic]
30-
public static unsafe float CompareExchange(ref float location1, float value, float comparand)
31-
{
32-
float ret;
33-
*(int*)&ret = CompareExchange(ref Unsafe.As<float, int>(ref location1), *(int*)&value, *(int*)&comparand);
34-
return ret;
35-
}
36-
37-
[Intrinsic]
38-
public static unsafe double CompareExchange(ref double location1, double value, double comparand)
39-
{
40-
double ret;
41-
*(long*)&ret = CompareExchange(ref Unsafe.As<double, long>(ref location1), *(long*)&value, *(long*)&comparand);
42-
return ret;
43-
}
44-
4526
[Intrinsic]
4627
[MethodImpl(MethodImplOptions.AggressiveInlining)]
4728
[return: NotNullIfNotNull(nameof(location1))]
@@ -87,22 +68,6 @@ public static long Exchange(ref long location1, long value)
8768
return oldValue;
8869
}
8970

90-
[Intrinsic]
91-
public static unsafe float Exchange(ref float location1, float value)
92-
{
93-
float ret;
94-
*(int*)&ret = Exchange(ref Unsafe.As<float, int>(ref location1), *(int*)&value);
95-
return ret;
96-
}
97-
98-
[Intrinsic]
99-
public static unsafe double Exchange(ref double location1, double value)
100-
{
101-
double ret;
102-
*(long*)&ret = Exchange(ref Unsafe.As<double, long>(ref location1), *(long*)&value);
103-
return ret;
104-
}
105-
10671
[Intrinsic]
10772
[MethodImpl(MethodImplOptions.AggressiveInlining)]
10873
[return: NotNullIfNotNull(nameof(location1))]

src/coreclr/vm/comutilnative.cpp

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,59 +1523,6 @@ FCIMPL3_IVV(INT64, COMInterlocked::CompareExchange64, INT64* location, INT64 val
15231523
}
15241524
FCIMPLEND
15251525

1526-
FCIMPL2_IV(float,COMInterlocked::ExchangeFloat, float *location, float value)
1527-
{
1528-
FCALL_CONTRACT;
1529-
1530-
if( NULL == location) {
1531-
FCThrow(kNullReferenceException);
1532-
}
1533-
1534-
LONG ret = InterlockedExchange((LONG *) location, *(LONG*)&value);
1535-
return *(float*)&ret;
1536-
}
1537-
FCIMPLEND
1538-
1539-
FCIMPL2_IV(double,COMInterlocked::ExchangeDouble, double *location, double value)
1540-
{
1541-
FCALL_CONTRACT;
1542-
1543-
if( NULL == location) {
1544-
FCThrow(kNullReferenceException);
1545-
}
1546-
1547-
1548-
INT64 ret = InterlockedExchange64((INT64 *) location, *(INT64*)&value);
1549-
return *(double*)&ret;
1550-
}
1551-
FCIMPLEND
1552-
1553-
FCIMPL3_IVV(float,COMInterlocked::CompareExchangeFloat, float *location, float value, float comparand)
1554-
{
1555-
FCALL_CONTRACT;
1556-
1557-
if( NULL == location) {
1558-
FCThrow(kNullReferenceException);
1559-
}
1560-
1561-
LONG ret = (LONG)InterlockedCompareExchange((LONG*) location, *(LONG*)&value, *(LONG*)&comparand);
1562-
return *(float*)&ret;
1563-
}
1564-
FCIMPLEND
1565-
1566-
FCIMPL3_IVV(double,COMInterlocked::CompareExchangeDouble, double *location, double value, double comparand)
1567-
{
1568-
FCALL_CONTRACT;
1569-
1570-
if( NULL == location) {
1571-
FCThrow(kNullReferenceException);
1572-
}
1573-
1574-
INT64 ret = (INT64)InterlockedCompareExchange64((INT64*) location, *(INT64*)&value, *(INT64*)&comparand);
1575-
return *(double*)&ret;
1576-
}
1577-
FCIMPLEND
1578-
15791526
FCIMPL2(LPVOID,COMInterlocked::ExchangeObject, LPVOID*location, LPVOID value)
15801527
{
15811528
FCALL_CONTRACT;

src/coreclr/vm/comutilnative.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,6 @@ class COMInterlocked
227227
static FCDECL2_IV(INT64, Exchange64, INT64 *location, INT64 value);
228228
static FCDECL3(INT32, CompareExchange, INT32* location, INT32 value, INT32 comparand);
229229
static FCDECL3_IVV(INT64, CompareExchange64, INT64* location, INT64 value, INT64 comparand);
230-
static FCDECL2_IV(float, ExchangeFloat, float *location, float value);
231-
static FCDECL2_IV(double, ExchangeDouble, double *location, double value);
232-
static FCDECL3_IVV(float, CompareExchangeFloat, float *location, float value, float comparand);
233-
static FCDECL3_IVV(double, CompareExchangeDouble, double *location, double value, double comparand);
234230
static FCDECL2(LPVOID, ExchangeObject, LPVOID* location, LPVOID value);
235231
static FCDECL3(LPVOID, CompareExchangeObject, LPVOID* location, LPVOID value, LPVOID comparand);
236232
static FCDECL2(INT32, ExchangeAdd32, INT32 *location, INT32 value);

src/coreclr/vm/ecalllist.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -509,13 +509,9 @@ FCFuncEnd()
509509
FCFuncStart(gInterlockedFuncs)
510510
FCFuncElementSig("Exchange", &gsig_SM_RefInt_Int_RetInt, COMInterlocked::Exchange)
511511
FCFuncElementSig("Exchange", &gsig_SM_RefLong_Long_RetLong, COMInterlocked::Exchange64)
512-
FCFuncElementSig("Exchange", &gsig_SM_RefDbl_Dbl_RetDbl, COMInterlocked::ExchangeDouble)
513-
FCFuncElementSig("Exchange", &gsig_SM_RefFlt_Flt_RetFlt, COMInterlocked::ExchangeFloat)
514512
FCFuncElementSig("Exchange", &gsig_SM_RefObj_Obj_RetObj, COMInterlocked::ExchangeObject)
515513
FCFuncElementSig("CompareExchange", &gsig_SM_RefInt_Int_Int_RetInt, COMInterlocked::CompareExchange)
516514
FCFuncElementSig("CompareExchange", &gsig_SM_RefLong_Long_Long_RetLong, COMInterlocked::CompareExchange64)
517-
FCFuncElementSig("CompareExchange", &gsig_SM_RefDbl_Dbl_Dbl_RetDbl, COMInterlocked::CompareExchangeDouble)
518-
FCFuncElementSig("CompareExchange", &gsig_SM_RefFlt_Flt_Flt_RetFlt, COMInterlocked::CompareExchangeFloat)
519515
FCFuncElementSig("CompareExchange", &gsig_SM_RefObj_Obj_Obj_RetObj, COMInterlocked::CompareExchangeObject)
520516
FCFuncElementSig("ExchangeAdd", &gsig_SM_RefInt_Int_RetInt, COMInterlocked::ExchangeAdd32)
521517
FCFuncElementSig("ExchangeAdd", &gsig_SM_RefLong_Long_RetLong, COMInterlocked::ExchangeAdd64)

src/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,24 @@ public static uint Exchange(ref uint location1, uint value) =>
6969
public static ulong Exchange(ref ulong location1, ulong value) =>
7070
(ulong)Exchange(ref Unsafe.As<ulong, long>(ref location1), (long)value);
7171

72+
/// <summary>Sets a single-precision floating point number to a specified value and returns the original value, as an atomic operation.</summary>
73+
/// <param name="location1">The variable to set to the specified value.</param>
74+
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
75+
/// <returns>The original value of <paramref name="location1"/>.</returns>
76+
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
77+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
78+
public static float Exchange(ref float location1, float value)
79+
=> Unsafe.BitCast<int, float>(Exchange(ref Unsafe.As<float, int>(ref location1), Unsafe.BitCast<float, int>(value)));
80+
81+
/// <summary>Sets a double-precision floating point number to a specified value and returns the original value, as an atomic operation.</summary>
82+
/// <param name="location1">The variable to set to the specified value.</param>
83+
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
84+
/// <returns>The original value of <paramref name="location1"/>.</returns>
85+
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
86+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
87+
public static double Exchange(ref double location1, double value)
88+
=> Unsafe.BitCast<long, double>(Exchange(ref Unsafe.As<double, long>(ref location1), Unsafe.BitCast<double, long>(value)));
89+
7290
/// <summary>Sets a platform-specific handle or pointer to a specified value and returns the original value, as an atomic operation.</summary>
7391
/// <param name="location1">The variable to set to the specified value.</param>
7492
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
@@ -126,6 +144,26 @@ public static uint CompareExchange(ref uint location1, uint value, uint comparan
126144
public static ulong CompareExchange(ref ulong location1, ulong value, ulong comparand) =>
127145
(ulong)CompareExchange(ref Unsafe.As<ulong, long>(ref location1), (long)value, (long)comparand);
128146

147+
/// <summary>Compares two single-precision floating point numbers for equality and, if they are equal, replaces the first value.</summary>
148+
/// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
149+
/// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
150+
/// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
151+
/// <returns>The original value in <paramref name="location1"/>.</returns>
152+
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
153+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
154+
public static float CompareExchange(ref float location1, float value, float comparand)
155+
=> Unsafe.BitCast<int, float>(CompareExchange(ref Unsafe.As<float, int>(ref location1), Unsafe.BitCast<float, int>(value), Unsafe.BitCast<float, int>(comparand)));
156+
157+
/// <summary>Compares two double-precision floating point numbers for equality and, if they are equal, replaces the first value.</summary>
158+
/// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
159+
/// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
160+
/// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
161+
/// <returns>The original value in <paramref name="location1"/>.</returns>
162+
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
163+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
164+
public static double CompareExchange(ref double location1, double value, double comparand)
165+
=> Unsafe.BitCast<long, double>(CompareExchange(ref Unsafe.As<double, long>(ref location1), Unsafe.BitCast<double, long>(value), Unsafe.BitCast<double, long>(comparand)));
166+
129167
/// <summary>Compares two platform-specific handles or pointers for equality and, if they are equal, replaces the first one.</summary>
130168
/// <param name="location1">The destination <see cref="IntPtr"/>, whose value is compared with the value of <paramref name="comparand"/> and possibly replaced by <paramref name="value"/>.</param>
131169
/// <param name="value">The <see cref="IntPtr"/> that replaces the destination value if the comparison results in equality.</param>

src/mono/System.Private.CoreLib/src/System/Threading/Interlocked.Mono.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ public static partial class Interlocked
3737
return result;
3838
}
3939

40-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
41-
public static extern float CompareExchange(ref float location1, float value, float comparand);
42-
4340
[Intrinsic]
4441
[MethodImplAttribute(MethodImplOptions.InternalCall)]
4542
public static extern int Decrement(ref int location);
@@ -72,16 +69,9 @@ public static partial class Interlocked
7269
return result;
7370
}
7471

75-
[Intrinsic]
76-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
77-
public static extern float Exchange(ref float location1, float value);
78-
7972
[MethodImplAttribute(MethodImplOptions.InternalCall)]
8073
public static extern long CompareExchange(ref long location1, long value, long comparand);
8174

82-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
83-
public static extern double CompareExchange(ref double location1, double value, double comparand);
84-
8575
[return: NotNullIfNotNull(nameof(location1))]
8676
[Intrinsic]
8777
public static T CompareExchange<T>(ref T location1, T value, T comparand) where T : class?
@@ -110,10 +100,6 @@ public static T CompareExchange<T>(ref T location1, T value, T comparand) where
110100
[MethodImplAttribute(MethodImplOptions.InternalCall)]
111101
public static extern long Exchange(ref long location1, long value);
112102

113-
[Intrinsic]
114-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
115-
public static extern double Exchange(ref double location1, double value);
116-
117103
[return: NotNullIfNotNull(nameof(location1))]
118104
[Intrinsic]
119105
public static T Exchange<T>([NotNullIfNotNull(nameof(value))] ref T location1, T value) where T : class?

src/mono/mono/metadata/icall-def.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -549,19 +549,15 @@ HANDLES(STRING_11, "InternalIsInterned", ves_icall_System_String_InternalIsInter
549549
ICALL_TYPE(ILOCK, "System.Threading.Interlocked", ILOCK_1)
550550
NOHANDLES(ICALL(ILOCK_1, "Add(int&,int)", ves_icall_System_Threading_Interlocked_Add_Int))
551551
NOHANDLES(ICALL(ILOCK_2, "Add(long&,long)", ves_icall_System_Threading_Interlocked_Add_Long))
552-
NOHANDLES(ICALL(ILOCK_4, "CompareExchange(double&,double,double)", ves_icall_System_Threading_Interlocked_CompareExchange_Double))
553552
NOHANDLES(ICALL(ILOCK_5, "CompareExchange(int&,int,int)", ves_icall_System_Threading_Interlocked_CompareExchange_Int))
554553
NOHANDLES(ICALL(ILOCK_6, "CompareExchange(int&,int,int,bool&)", ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success))
555554
NOHANDLES(ICALL(ILOCK_8, "CompareExchange(long&,long,long)", ves_icall_System_Threading_Interlocked_CompareExchange_Long))
556555
NOHANDLES(ICALL(ILOCK_9, "CompareExchange(object&,object&,object&,object&)", ves_icall_System_Threading_Interlocked_CompareExchange_Object))
557-
NOHANDLES(ICALL(ILOCK_10, "CompareExchange(single&,single,single)", ves_icall_System_Threading_Interlocked_CompareExchange_Single))
558556
NOHANDLES(ICALL(ILOCK_11, "Decrement(int&)", ves_icall_System_Threading_Interlocked_Decrement_Int))
559557
NOHANDLES(ICALL(ILOCK_12, "Decrement(long&)", ves_icall_System_Threading_Interlocked_Decrement_Long))
560-
NOHANDLES(ICALL(ILOCK_14, "Exchange(double&,double)", ves_icall_System_Threading_Interlocked_Exchange_Double))
561558
NOHANDLES(ICALL(ILOCK_15, "Exchange(int&,int)", ves_icall_System_Threading_Interlocked_Exchange_Int))
562559
NOHANDLES(ICALL(ILOCK_17, "Exchange(long&,long)", ves_icall_System_Threading_Interlocked_Exchange_Long))
563560
NOHANDLES(ICALL(ILOCK_18, "Exchange(object&,object&,object&)", ves_icall_System_Threading_Interlocked_Exchange_Object))
564-
NOHANDLES(ICALL(ILOCK_19, "Exchange(single&,single)", ves_icall_System_Threading_Interlocked_Exchange_Single))
565561
NOHANDLES(ICALL(ILOCK_20, "Increment(int&)", ves_icall_System_Threading_Interlocked_Increment_Int))
566562
NOHANDLES(ICALL(ILOCK_21, "Increment(long&)", ves_icall_System_Threading_Interlocked_Increment_Long))
567563
NOHANDLES(ICALL(ILOCK_22, "MemoryBarrierProcessWide", ves_icall_System_Threading_Interlocked_MemoryBarrierProcessWide))

0 commit comments

Comments
 (0)