Use half-fences for volatile loads/stores on Windows ARM64 (dotnet/coreclr#27384)
authorVladimir Sadov <vsadov@microsoft.com>
Fri, 25 Oct 2019 17:14:45 +0000 (10:14 -0700)
committerJan Kotas <jkotas@microsoft.com>
Fri, 25 Oct 2019 17:14:45 +0000 (10:14 -0700)
* Use half-fences for volatile load/stores on Windows ARM64

* Updated Volatile.h in gc/env as well.
unified on type names and warning suppression.

Commit migrated from https://github.com/dotnet/coreclr/commit/c128dbacaac207364b01c2d16890031e5aab47a4

src/coreclr/src/gc/env/volatile.h
src/coreclr/src/inc/volatile.h

index 311e126..de613ad 100644 (file)
@@ -127,6 +127,9 @@ struct RemoveVolatile<volatile T>
 // Starting at version 3.8, clang errors out on initializing of type int * to volatile int *. To fix this, we add two templates to cast away volatility
 // Helper structures for casting away volatileness
 
+#if defined(_ARM64_) && defined(_MSC_VER)
+#include <arm64intr.h>
+#endif
 
 template<typename T>
 inline
@@ -145,6 +148,32 @@ T VolatileLoad(T const * pt)
         val = *(T volatile const *)pt;
         asm volatile ("dmb ishld" : : : "memory");
     }
+#elif defined(_ARM64_) && defined(_MSC_VER)
+// silence warnings on casts in branches that are not taken.
+#pragma warning(push)
+#pragma warning(disable : 4302)
+#pragma warning(disable : 4311)
+#pragma warning(disable : 4312)
+    T val;
+    switch (sizeof(T))
+    {
+    case 1:
+        val = (typename RemoveVolatile<T>::type)__ldar8 ((unsigned __int8  volatile*)pt);
+        break;
+    case 2:
+        val = (typename RemoveVolatile<T>::type)__ldar16((unsigned __int16 volatile*)pt);
+        break;
+    case 4:
+        val = (typename RemoveVolatile<T>::type)__ldar32((unsigned __int32 volatile*)pt);
+        break;
+    case 8:
+        val = (typename RemoveVolatile<T>::type)__ldar64((unsigned __int64 volatile*)pt);
+        break;
+    default:
+        val = *(T volatile const*)pt;
+        __dmb(_ARM64_BARRIER_ISHLD);
+    }
+#pragma warning(pop)
 #else
     T val = *(T volatile const *)pt;
     VOLATILE_MEMORY_BARRIER();
@@ -199,6 +228,31 @@ void VolatileStore(T* pt, T val)
         VOLATILE_MEMORY_BARRIER();
         *(T volatile *)pt = val;
     }
+#elif defined(_ARM64_) && defined(_MSC_VER)
+// silence warnings on casts in branches that are not taken.
+#pragma warning(push)
+#pragma warning(disable : 4302)
+#pragma warning(disable : 4311)
+#pragma warning(disable : 4312)
+    switch (sizeof(T))
+    {
+    case 1:
+        __stlr8 ((unsigned __int8  volatile*)pt, (unsigned __int8) val);
+        break;
+    case 2:
+        __stlr16((unsigned __int16 volatile*)pt, (unsigned __int16)val);
+        break;
+    case 4:
+        __stlr32((unsigned __int32 volatile*)pt, (unsigned __int32)val);
+        break;
+    case 8:
+        __stlr64((unsigned __int64 volatile*)pt ,(unsigned __int64)val);
+        break;
+    default:
+        __dmb(_ARM64_BARRIER_ISH);
+        *(T volatile *)pt = val;
+    }
+#pragma warning(pop)
 #else
     VOLATILE_MEMORY_BARRIER();
     *(T volatile *)pt = val;
index fa756ef..c6355fc 100644 (file)
@@ -129,6 +129,9 @@ struct RemoveVolatile<volatile T>
 // Starting at version 3.8, clang errors out on initializing of type int * to volatile int *. To fix this, we add two templates to cast away volatility
 // Helper structures for casting away volatileness
 
+#if defined(_ARM64_) && defined(_MSC_VER)
+#include <arm64intr.h>
+#endif
 
 template<typename T>
 inline
@@ -149,6 +152,32 @@ T VolatileLoad(T const * pt)
         val = *(T volatile const *)pt;
         asm volatile ("dmb ishld" : : : "memory");
     }
+#elif defined(_ARM64_) && defined(_MSC_VER)
+// silence warnings on casts in branches that are not taken.
+#pragma warning(push)
+#pragma warning(disable : 4302)
+#pragma warning(disable : 4311)
+#pragma warning(disable : 4312)
+    T val;
+    switch (sizeof(T))
+    {
+    case 1:
+        val = (typename RemoveVolatile<T>::type)__ldar8 ((unsigned __int8   volatile*)pt);
+        break;
+    case 2:
+        val = (typename RemoveVolatile<T>::type)__ldar16((unsigned __int16  volatile*)pt);
+        break;
+    case 4:
+        val = (typename RemoveVolatile<T>::type)__ldar32((unsigned __int32  volatile*)pt);
+        break;
+    case 8:
+        val = (typename RemoveVolatile<T>::type)__ldar64((unsigned __int64  volatile*)pt);
+        break;
+    default:
+        val = *(T volatile const*)pt;
+        __dmb(_ARM64_BARRIER_ISHLD);
+    }
+#pragma warning(pop)
 #else
     T val = *(T volatile const *)pt;
     VOLATILE_MEMORY_BARRIER();
@@ -208,6 +237,31 @@ void VolatileStore(T* pt, T val)
         VOLATILE_MEMORY_BARRIER();
         *(T volatile *)pt = val;
     }
+#elif defined(_ARM64_) && defined(_MSC_VER)
+// silence warnings on casts in branches that are not taken.
+#pragma warning(push)
+#pragma warning(disable : 4302)
+#pragma warning(disable : 4311)
+#pragma warning(disable : 4312)
+    switch (sizeof(T))
+    {
+    case 1:
+        __stlr8 ((unsigned __int8   volatile*)pt, (unsigned __int8) val);
+        break;
+    case 2:
+        __stlr16((unsigned __int16  volatile*)pt, (unsigned __int16)val);
+        break;
+    case 4:
+        __stlr32((unsigned __int32  volatile*)pt, (unsigned __int32)val);
+        break;
+    case 8:
+        __stlr64((unsigned __int64  volatile*)pt ,(unsigned __int64)val);
+        break;
+    default:
+        __dmb(_ARM64_BARRIER_ISH);
+        *(T volatile *)pt = val;
+    }
+#pragma warning(pop)
 #else
     VOLATILE_MEMORY_BARRIER();
     *(T volatile *)pt = val;