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

Interlocked intrinsic improvements #93821

Merged
merged 2 commits into from
Oct 27, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ public static partial class Interlocked
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
/// <typeparam name="T">The type to be used for <paramref name="location1"/> and <paramref name="value"/>. This type must be a reference type.</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Intrinsic]
[return: NotNullIfNotNull(nameof(location1))]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Exchange<T>([NotNullIfNotNull(nameof(value))] ref T location1, T value) where T : class? =>
Unsafe.As<T>(Exchange(ref Unsafe.As<T, object?>(ref location1), value));
#endregion
Expand Down Expand Up @@ -134,8 +135,9 @@ public static partial class Interlocked
/// <returns>The original value in <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
/// <typeparam name="T">The type to be used for <paramref name="location1"/>, <paramref name="value"/>, and <paramref name="comparand"/>. This type must be a reference type.</typeparam>
[return: NotNullIfNotNull(nameof(location1))]
[Intrinsic]
[return: NotNullIfNotNull(nameof(location1))]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T CompareExchange<T>(ref T location1, T value, T comparand) where T : class? =>
Unsafe.As<T>(CompareExchange(ref Unsafe.As<T, object?>(ref location1), value, comparand));
#endregion
Expand Down
20 changes: 12 additions & 8 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3253,16 +3253,18 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
case NI_System_Threading_Interlocked_CompareExchange:
{
var_types retType = JITtype2varType(sig->retType);
if ((retType == TYP_LONG) && (TARGET_POINTER_SIZE == 4))
if (genTypeSize(retType) > TARGET_POINTER_SIZE)
{
break;
}
if ((retType == TYP_REF) && impStackTop(1).val->IsIntegralConst(0))

if ((retType == TYP_REF) &&
(impStackTop(1).val->IsIntegralConst(0) || impStackTop(1).val->IsIconHandle(GTF_ICON_OBJ_HDL)))
{
// Intrinsify "object" overload in case of null assignment
// since we don't need the write barrier.
}
else if ((retType != TYP_INT) && (retType != TYP_LONG))
else if (!varTypeIsIntegral(retType))
{
break;
}
Expand All @@ -3273,7 +3275,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
GenTree* op3 = impPopStack().val; // comparand
GenTree* op2 = impPopStack().val; // value
GenTree* op1 = impPopStack().val; // location
retNode = gtNewAtomicNode(GT_CMPXCHG, genActualType(callType), op1, op2, op3);
retNode = gtNewAtomicNode(GT_CMPXCHG, callType, op1, op2, op3);
break;
}

Expand All @@ -3284,17 +3286,19 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
assert(sig->numArgs == 2);

var_types retType = JITtype2varType(sig->retType);
if ((retType == TYP_LONG) && (TARGET_POINTER_SIZE == 4))
if (genTypeSize(retType) > TARGET_POINTER_SIZE)
{
break;
}
if ((retType == TYP_REF) && impStackTop().val->IsIntegralConst(0))

if ((retType == TYP_REF) &&
(impStackTop().val->IsIntegralConst(0) || impStackTop().val->IsIconHandle(GTF_ICON_OBJ_HDL)))
{
// Intrinsify "object" overload in case of null assignment
// since we don't need the write barrier.
assert(ni == NI_System_Threading_Interlocked_Exchange);
}
else if ((retType != TYP_INT) && (retType != TYP_LONG))
else if (!varTypeIsIntegral(retType))
{
break;
}
Expand All @@ -3308,7 +3312,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
// field_addr (for example)
//
retNode = gtNewAtomicNode(ni == NI_System_Threading_Interlocked_ExchangeAdd ? GT_XADD : GT_XCHG,
genActualType(callType), op1, op2);
callType, op1, op2);
break;
}
#endif // defined(TARGET_XARCH) || defined(TARGET_ARM64) || defined(TARGET_RISCV64)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public static long CompareExchange(ref long location1, long value, long comparan
}

[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[return: NotNullIfNotNull(nameof(location1))]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T CompareExchange<T>(ref T location1, T value, T comparand) where T : class?
{
return Unsafe.As<T>(RuntimeImports.InterlockedCompareExchange(ref Unsafe.As<T, object?>(ref location1), value, comparand));
Expand Down Expand Up @@ -69,8 +69,8 @@ public static long Exchange(ref long location1, long value)
}

[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[return: NotNullIfNotNull(nameof(location1))]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Exchange<T>([NotNullIfNotNull(nameof(value))] ref T location1, T value) where T : class?
{
return Unsafe.As<T>(RuntimeImports.InterlockedExchange(ref Unsafe.As<T, object?>(ref location1), value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public static partial class Interlocked
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
public static uint Exchange(ref uint location1, uint value) =>
Expand All @@ -64,6 +65,7 @@ public static partial class Interlocked
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
public static ulong Exchange(ref ulong location1, ulong value) =>
Expand Down Expand Up @@ -92,6 +94,7 @@ public static double Exchange(ref double location1, double value)
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IntPtr Exchange(ref IntPtr location1, IntPtr value)
{
Expand All @@ -109,6 +112,7 @@ public static IntPtr Exchange(ref IntPtr location1, IntPtr value)
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UIntPtr Exchange(ref UIntPtr location1, UIntPtr value)
Expand All @@ -128,6 +132,7 @@ public static UIntPtr Exchange(ref UIntPtr location1, UIntPtr value)
/// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
/// <returns>The original value in <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
public static uint CompareExchange(ref uint location1, uint value, uint comparand) =>
Expand All @@ -139,6 +144,7 @@ public static UIntPtr Exchange(ref UIntPtr location1, UIntPtr value)
/// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
/// <returns>The original value in <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
public static ulong CompareExchange(ref ulong location1, ulong value, ulong comparand) =>
Expand Down Expand Up @@ -170,6 +176,7 @@ public static double CompareExchange(ref double location1, double value, double
/// <param name="comparand">The <see cref="IntPtr"/> that is compared to the value at <paramref name="location1"/>.</param>
/// <returns>The original value in <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IntPtr CompareExchange(ref IntPtr location1, IntPtr value, IntPtr comparand)
{
Expand All @@ -188,6 +195,7 @@ public static IntPtr CompareExchange(ref IntPtr location1, IntPtr value, IntPtr
/// <param name="comparand">The <see cref="UIntPtr"/> that is compared to the value at <paramref name="location1"/>.</param>
/// <returns>The original value in <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
[Intrinsic]
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UIntPtr CompareExchange(ref UIntPtr location1, UIntPtr value, UIntPtr comparand)
Expand Down
Loading