diff --git a/src/coreclr/gc/env/gcenv.interlocked.h b/src/coreclr/gc/env/gcenv.interlocked.h index f04b428e51bd6c..e92a3bee0c75cd 100644 --- a/src/coreclr/gc/env/gcenv.interlocked.h +++ b/src/coreclr/gc/env/gcenv.interlocked.h @@ -6,6 +6,14 @@ #ifndef __GCENV_INTERLOCKED_H__ #define __GCENV_INTERLOCKED_H__ + +#if defined(TARGET_WINDOWS) && defined(TARGET_ARM64) +// Flag to check if atomics feature is available on +// the machine +extern bool g_arm64_atomics_present; +#endif + + // Interlocked operations class Interlocked { diff --git a/src/coreclr/gc/env/gcenv.interlocked.inl b/src/coreclr/gc/env/gcenv.interlocked.inl index 03d487a5320170..3f6a0832f225bb 100644 --- a/src/coreclr/gc/env/gcenv.interlocked.inl +++ b/src/coreclr/gc/env/gcenv.interlocked.inl @@ -70,7 +70,16 @@ __forceinline T Interlocked::Exchange(T volatile *destination, T value) { #ifdef _MSC_VER static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T"); - return _InterlockedExchange((long*)destination, value); +#ifdef TARGET_ARM64 + if (g_arm64_atomics_present) + { + return (T) __swpal32((unsigned __int32*) destination, (unsigned __int32)value); + } + else +#endif // TARGET_ARM64 + { + return _InterlockedExchange((long*)destination, value); + } #else T result = __atomic_exchange_n(destination, value, __ATOMIC_ACQ_REL); ArmInterlockedOperationBarrier(); @@ -91,12 +100,21 @@ __forceinline T Interlocked::CompareExchange(T volatile *destination, T exchange { #ifdef _MSC_VER static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T"); - return _InterlockedCompareExchange((long*)destination, exchange, comparand); +#ifdef TARGET_ARM64 + if (g_arm64_atomics_present) + { + return (T) __casal32((unsigned __int32*) destination, (unsigned __int32)comparand, (unsigned __int32)exchange); + } + else +#endif // TARGET_ARM64 + { + return _InterlockedCompareExchange((long*)destination, exchange, comparand); + } #else T result = __sync_val_compare_and_swap(destination, comparand, exchange); ArmInterlockedOperationBarrier(); return result; -#endif +#endif // _MSC_VER } // Perform an atomic addition of two 32-bit values and return the original value of the addend. @@ -192,15 +210,24 @@ __forceinline T Interlocked::ExchangePointer(T volatile * destination, T value) { #ifdef _MSC_VER #ifdef HOST_64BIT - return (T)(TADDR)_InterlockedExchangePointer((void* volatile *)destination, value); +#ifdef TARGET_ARM64 + if (g_arm64_atomics_present) + { + return (T)(TADDR)__swpal64((unsigned __int64 volatile*) destination, (unsigned __int64)value); + } + else +#endif // TARGET_ARM64 + { + return (T)(TADDR)_InterlockedExchangePointer((void* volatile *)destination, value); + } #else return (T)(TADDR)_InterlockedExchange((long volatile *)(void* volatile *)destination, (long)(void*)value); -#endif +#endif // HOST_64BIT #else T result = (T)(TADDR)__atomic_exchange_n((void* volatile *)destination, value, __ATOMIC_ACQ_REL); ArmInterlockedOperationBarrier(); return result; -#endif +#endif // _MSC_VER } template @@ -208,15 +235,24 @@ __forceinline T Interlocked::ExchangePointer(T volatile * destination, std::null { #ifdef _MSC_VER #ifdef HOST_64BIT - return (T)(TADDR)_InterlockedExchangePointer((void* volatile *)destination, value); +#ifdef TARGET_ARM64 + if (g_arm64_atomics_present) + { + return (T)(TADDR)__swpal64((unsigned __int64 volatile*) destination, (unsigned __int64)value); + } + else +#endif // TARGET_ARM64 + { + return (T)(TADDR)_InterlockedExchangePointer((void* volatile *)destination, value); + } #else return (T)(TADDR)_InterlockedExchange((long volatile *)(void* volatile *)destination, (long)(void*)value); -#endif +#endif // HOST_64BIT #else T result = (T)(TADDR)__atomic_exchange_n((void* volatile *)destination, value, __ATOMIC_ACQ_REL); ArmInterlockedOperationBarrier(); return result; -#endif +#endif // _MSC_VER } // Performs an atomic compare-and-exchange operation on the specified pointers. diff --git a/src/coreclr/gc/gccommon.cpp b/src/coreclr/gc/gccommon.cpp index 27eb8f935c3372..d4269df4f6ec6a 100644 --- a/src/coreclr/gc/gccommon.cpp +++ b/src/coreclr/gc/gccommon.cpp @@ -17,6 +17,13 @@ IGCHeapInternal* g_theGCHeap; IGCHandleManager* g_theGCHandleManager; #ifdef BUILD_AS_STANDALONE + +#if defined(TARGET_WINDOWS) && defined(TARGET_ARM64) +// Flag to check if atomics feature is available on +// the machine. OFF for standalone. +bool g_arm64_atomics_present = false; +#endif // defined(TARGET_WINDOWS) && defined(TARGET_ARM64) + IGCToCLR* g_theGCToCLR; #endif // BUILD_AS_STANDALONE diff --git a/src/coreclr/gc/sample/GCSample.cpp b/src/coreclr/gc/sample/GCSample.cpp index c102efc4ae71c6..ff96093911f4d3 100644 --- a/src/coreclr/gc/sample/GCSample.cpp +++ b/src/coreclr/gc/sample/GCSample.cpp @@ -40,6 +40,7 @@ #include "common.h" + #include "gcenv.h" #include "gc.h" @@ -47,6 +48,12 @@ #include "gcdesc.h" +#if defined(TARGET_WINDOWS) && defined(TARGET_ARM64) +// Flag to check if atomics feature is available on +// the machine. OFF for GCSample. +bool g_arm64_atomics_present = false; +#endif + // // The fast paths for object allocation and write barriers is performance critical. They are often // hand written in assembly code, etc. diff --git a/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp b/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp index 631fbb61c4dd50..eae8e5d4489b43 100644 --- a/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp +++ b/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp @@ -35,6 +35,12 @@ uint32_t PalEventWrite(REGHANDLE arg1, const EVENT_DESCRIPTOR * arg2, uint32_t a #define REDHAWK_PALEXPORT extern "C" #define REDHAWK_PALAPI __stdcall +#if defined(HOST_ARM64) +// Flag to check if atomics feature is available on +// the machine. OFF for GCSample. +bool g_arm64_atomics_present = false; +#endif + // Index for the fiber local storage of the attached thread pointer static uint32_t g_flsIndex = FLS_OUT_OF_INDEXES; @@ -690,6 +696,7 @@ REDHAWK_PALIMPORT void REDHAWK_PALAPI PAL_GetCpuCapabilityFlags(int* flags) if (IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)) { *flags |= ARM64IntrinsicConstants_Atomics; + g_arm64_atomics_present = true; } }