13cab2bb3Spatrick //===-- sanitizer_atomic_msvc.h ---------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
103cab2bb3Spatrick // Not intended for direct inclusion. Include sanitizer_atomic.h.
113cab2bb3Spatrick //
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick
143cab2bb3Spatrick #ifndef SANITIZER_ATOMIC_MSVC_H
153cab2bb3Spatrick #define SANITIZER_ATOMIC_MSVC_H
163cab2bb3Spatrick
173cab2bb3Spatrick extern "C" void _ReadWriteBarrier();
183cab2bb3Spatrick #pragma intrinsic(_ReadWriteBarrier)
193cab2bb3Spatrick extern "C" void _mm_mfence();
203cab2bb3Spatrick #pragma intrinsic(_mm_mfence)
213cab2bb3Spatrick extern "C" void _mm_pause();
223cab2bb3Spatrick #pragma intrinsic(_mm_pause)
233cab2bb3Spatrick extern "C" char _InterlockedExchange8(char volatile *Addend, char Value);
243cab2bb3Spatrick #pragma intrinsic(_InterlockedExchange8)
253cab2bb3Spatrick extern "C" short _InterlockedExchange16(short volatile *Addend, short Value);
263cab2bb3Spatrick #pragma intrinsic(_InterlockedExchange16)
273cab2bb3Spatrick extern "C" long _InterlockedExchange(long volatile *Addend, long Value);
283cab2bb3Spatrick #pragma intrinsic(_InterlockedExchange)
293cab2bb3Spatrick extern "C" long _InterlockedExchangeAdd(long volatile *Addend, long Value);
303cab2bb3Spatrick #pragma intrinsic(_InterlockedExchangeAdd)
313cab2bb3Spatrick extern "C" char _InterlockedCompareExchange8(char volatile *Destination,
323cab2bb3Spatrick char Exchange, char Comparand);
333cab2bb3Spatrick #pragma intrinsic(_InterlockedCompareExchange8)
343cab2bb3Spatrick extern "C" short _InterlockedCompareExchange16(short volatile *Destination,
353cab2bb3Spatrick short Exchange, short Comparand);
363cab2bb3Spatrick #pragma intrinsic(_InterlockedCompareExchange16)
373cab2bb3Spatrick extern "C" long long _InterlockedCompareExchange64(
383cab2bb3Spatrick long long volatile *Destination, long long Exchange, long long Comparand);
393cab2bb3Spatrick #pragma intrinsic(_InterlockedCompareExchange64)
403cab2bb3Spatrick extern "C" void *_InterlockedCompareExchangePointer(
413cab2bb3Spatrick void *volatile *Destination,
423cab2bb3Spatrick void *Exchange, void *Comparand);
433cab2bb3Spatrick #pragma intrinsic(_InterlockedCompareExchangePointer)
443cab2bb3Spatrick extern "C" long __cdecl _InterlockedCompareExchange(long volatile *Destination,
453cab2bb3Spatrick long Exchange,
463cab2bb3Spatrick long Comparand);
473cab2bb3Spatrick #pragma intrinsic(_InterlockedCompareExchange)
483cab2bb3Spatrick
493cab2bb3Spatrick #ifdef _WIN64
503cab2bb3Spatrick extern "C" long long _InterlockedExchangeAdd64(long long volatile *Addend,
513cab2bb3Spatrick long long Value);
523cab2bb3Spatrick #pragma intrinsic(_InterlockedExchangeAdd64)
533cab2bb3Spatrick #endif
543cab2bb3Spatrick
553cab2bb3Spatrick namespace __sanitizer {
563cab2bb3Spatrick
atomic_signal_fence(memory_order)57*d89ec533Spatrick inline void atomic_signal_fence(memory_order) {
583cab2bb3Spatrick _ReadWriteBarrier();
593cab2bb3Spatrick }
603cab2bb3Spatrick
atomic_thread_fence(memory_order)61*d89ec533Spatrick inline void atomic_thread_fence(memory_order) {
623cab2bb3Spatrick _mm_mfence();
633cab2bb3Spatrick }
643cab2bb3Spatrick
proc_yield(int cnt)65*d89ec533Spatrick inline void proc_yield(int cnt) {
663cab2bb3Spatrick for (int i = 0; i < cnt; i++)
673cab2bb3Spatrick _mm_pause();
683cab2bb3Spatrick }
693cab2bb3Spatrick
703cab2bb3Spatrick template<typename T>
atomic_load(const volatile T * a,memory_order mo)71*d89ec533Spatrick inline typename T::Type atomic_load(
723cab2bb3Spatrick const volatile T *a, memory_order mo) {
733cab2bb3Spatrick DCHECK(mo & (memory_order_relaxed | memory_order_consume
743cab2bb3Spatrick | memory_order_acquire | memory_order_seq_cst));
753cab2bb3Spatrick DCHECK(!((uptr)a % sizeof(*a)));
763cab2bb3Spatrick typename T::Type v;
773cab2bb3Spatrick // FIXME(dvyukov): 64-bit load is not atomic on 32-bits.
783cab2bb3Spatrick if (mo == memory_order_relaxed) {
793cab2bb3Spatrick v = a->val_dont_use;
803cab2bb3Spatrick } else {
813cab2bb3Spatrick atomic_signal_fence(memory_order_seq_cst);
823cab2bb3Spatrick v = a->val_dont_use;
833cab2bb3Spatrick atomic_signal_fence(memory_order_seq_cst);
843cab2bb3Spatrick }
853cab2bb3Spatrick return v;
863cab2bb3Spatrick }
873cab2bb3Spatrick
883cab2bb3Spatrick template<typename T>
atomic_store(volatile T * a,typename T::Type v,memory_order mo)89*d89ec533Spatrick inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
903cab2bb3Spatrick DCHECK(mo & (memory_order_relaxed | memory_order_release
913cab2bb3Spatrick | memory_order_seq_cst));
923cab2bb3Spatrick DCHECK(!((uptr)a % sizeof(*a)));
933cab2bb3Spatrick // FIXME(dvyukov): 64-bit store is not atomic on 32-bits.
943cab2bb3Spatrick if (mo == memory_order_relaxed) {
953cab2bb3Spatrick a->val_dont_use = v;
963cab2bb3Spatrick } else {
973cab2bb3Spatrick atomic_signal_fence(memory_order_seq_cst);
983cab2bb3Spatrick a->val_dont_use = v;
993cab2bb3Spatrick atomic_signal_fence(memory_order_seq_cst);
1003cab2bb3Spatrick }
1013cab2bb3Spatrick if (mo == memory_order_seq_cst)
1023cab2bb3Spatrick atomic_thread_fence(memory_order_seq_cst);
1033cab2bb3Spatrick }
1043cab2bb3Spatrick
atomic_fetch_add(volatile atomic_uint32_t * a,u32 v,memory_order mo)105*d89ec533Spatrick inline u32 atomic_fetch_add(volatile atomic_uint32_t *a,
1063cab2bb3Spatrick u32 v, memory_order mo) {
1073cab2bb3Spatrick (void)mo;
1083cab2bb3Spatrick DCHECK(!((uptr)a % sizeof(*a)));
1093cab2bb3Spatrick return (u32)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use,
1103cab2bb3Spatrick (long)v);
1113cab2bb3Spatrick }
1123cab2bb3Spatrick
atomic_fetch_add(volatile atomic_uintptr_t * a,uptr v,memory_order mo)113*d89ec533Spatrick inline uptr atomic_fetch_add(volatile atomic_uintptr_t *a,
1143cab2bb3Spatrick uptr v, memory_order mo) {
1153cab2bb3Spatrick (void)mo;
1163cab2bb3Spatrick DCHECK(!((uptr)a % sizeof(*a)));
1173cab2bb3Spatrick #ifdef _WIN64
1183cab2bb3Spatrick return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use,
1193cab2bb3Spatrick (long long)v);
1203cab2bb3Spatrick #else
1213cab2bb3Spatrick return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use,
1223cab2bb3Spatrick (long)v);
1233cab2bb3Spatrick #endif
1243cab2bb3Spatrick }
1253cab2bb3Spatrick
atomic_fetch_sub(volatile atomic_uint32_t * a,u32 v,memory_order mo)126*d89ec533Spatrick inline u32 atomic_fetch_sub(volatile atomic_uint32_t *a,
1273cab2bb3Spatrick u32 v, memory_order mo) {
1283cab2bb3Spatrick (void)mo;
1293cab2bb3Spatrick DCHECK(!((uptr)a % sizeof(*a)));
1303cab2bb3Spatrick return (u32)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use,
1313cab2bb3Spatrick -(long)v);
1323cab2bb3Spatrick }
1333cab2bb3Spatrick
atomic_fetch_sub(volatile atomic_uintptr_t * a,uptr v,memory_order mo)134*d89ec533Spatrick inline uptr atomic_fetch_sub(volatile atomic_uintptr_t *a,
1353cab2bb3Spatrick uptr v, memory_order mo) {
1363cab2bb3Spatrick (void)mo;
1373cab2bb3Spatrick DCHECK(!((uptr)a % sizeof(*a)));
1383cab2bb3Spatrick #ifdef _WIN64
1393cab2bb3Spatrick return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use,
1403cab2bb3Spatrick -(long long)v);
1413cab2bb3Spatrick #else
1423cab2bb3Spatrick return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use,
1433cab2bb3Spatrick -(long)v);
1443cab2bb3Spatrick #endif
1453cab2bb3Spatrick }
1463cab2bb3Spatrick
atomic_exchange(volatile atomic_uint8_t * a,u8 v,memory_order mo)147*d89ec533Spatrick inline u8 atomic_exchange(volatile atomic_uint8_t *a,
1483cab2bb3Spatrick u8 v, memory_order mo) {
1493cab2bb3Spatrick (void)mo;
1503cab2bb3Spatrick DCHECK(!((uptr)a % sizeof(*a)));
1513cab2bb3Spatrick return (u8)_InterlockedExchange8((volatile char*)&a->val_dont_use, v);
1523cab2bb3Spatrick }
1533cab2bb3Spatrick
atomic_exchange(volatile atomic_uint16_t * a,u16 v,memory_order mo)154*d89ec533Spatrick inline u16 atomic_exchange(volatile atomic_uint16_t *a,
1553cab2bb3Spatrick u16 v, memory_order mo) {
1563cab2bb3Spatrick (void)mo;
1573cab2bb3Spatrick DCHECK(!((uptr)a % sizeof(*a)));
1583cab2bb3Spatrick return (u16)_InterlockedExchange16((volatile short*)&a->val_dont_use, v);
1593cab2bb3Spatrick }
1603cab2bb3Spatrick
atomic_exchange(volatile atomic_uint32_t * a,u32 v,memory_order mo)161*d89ec533Spatrick inline u32 atomic_exchange(volatile atomic_uint32_t *a,
1623cab2bb3Spatrick u32 v, memory_order mo) {
1633cab2bb3Spatrick (void)mo;
1643cab2bb3Spatrick DCHECK(!((uptr)a % sizeof(*a)));
1653cab2bb3Spatrick return (u32)_InterlockedExchange((volatile long*)&a->val_dont_use, v);
1663cab2bb3Spatrick }
1673cab2bb3Spatrick
atomic_compare_exchange_strong(volatile atomic_uint8_t * a,u8 * cmp,u8 xchgv,memory_order mo)168*d89ec533Spatrick inline bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
1693cab2bb3Spatrick u8 *cmp,
1703cab2bb3Spatrick u8 xchgv,
1713cab2bb3Spatrick memory_order mo) {
1723cab2bb3Spatrick (void)mo;
1733cab2bb3Spatrick DCHECK(!((uptr)a % sizeof(*a)));
1743cab2bb3Spatrick u8 cmpv = *cmp;
1753cab2bb3Spatrick #ifdef _WIN64
1763cab2bb3Spatrick u8 prev = (u8)_InterlockedCompareExchange8(
1773cab2bb3Spatrick (volatile char*)&a->val_dont_use, (char)xchgv, (char)cmpv);
1783cab2bb3Spatrick #else
1793cab2bb3Spatrick u8 prev;
1803cab2bb3Spatrick __asm {
1813cab2bb3Spatrick mov al, cmpv
1823cab2bb3Spatrick mov ecx, a
1833cab2bb3Spatrick mov dl, xchgv
1843cab2bb3Spatrick lock cmpxchg [ecx], dl
1853cab2bb3Spatrick mov prev, al
1863cab2bb3Spatrick }
1873cab2bb3Spatrick #endif
1883cab2bb3Spatrick if (prev == cmpv)
1893cab2bb3Spatrick return true;
1903cab2bb3Spatrick *cmp = prev;
1913cab2bb3Spatrick return false;
1923cab2bb3Spatrick }
1933cab2bb3Spatrick
atomic_compare_exchange_strong(volatile atomic_uintptr_t * a,uptr * cmp,uptr xchg,memory_order mo)194*d89ec533Spatrick inline bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
1953cab2bb3Spatrick uptr *cmp,
1963cab2bb3Spatrick uptr xchg,
1973cab2bb3Spatrick memory_order mo) {
1983cab2bb3Spatrick uptr cmpv = *cmp;
1993cab2bb3Spatrick uptr prev = (uptr)_InterlockedCompareExchangePointer(
2003cab2bb3Spatrick (void*volatile*)&a->val_dont_use, (void*)xchg, (void*)cmpv);
2013cab2bb3Spatrick if (prev == cmpv)
2023cab2bb3Spatrick return true;
2033cab2bb3Spatrick *cmp = prev;
2043cab2bb3Spatrick return false;
2053cab2bb3Spatrick }
2063cab2bb3Spatrick
atomic_compare_exchange_strong(volatile atomic_uint16_t * a,u16 * cmp,u16 xchg,memory_order mo)207*d89ec533Spatrick inline bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a,
2083cab2bb3Spatrick u16 *cmp,
2093cab2bb3Spatrick u16 xchg,
2103cab2bb3Spatrick memory_order mo) {
2113cab2bb3Spatrick u16 cmpv = *cmp;
2123cab2bb3Spatrick u16 prev = (u16)_InterlockedCompareExchange16(
2133cab2bb3Spatrick (volatile short*)&a->val_dont_use, (short)xchg, (short)cmpv);
2143cab2bb3Spatrick if (prev == cmpv)
2153cab2bb3Spatrick return true;
2163cab2bb3Spatrick *cmp = prev;
2173cab2bb3Spatrick return false;
2183cab2bb3Spatrick }
2193cab2bb3Spatrick
atomic_compare_exchange_strong(volatile atomic_uint32_t * a,u32 * cmp,u32 xchg,memory_order mo)220*d89ec533Spatrick inline bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a,
2213cab2bb3Spatrick u32 *cmp,
2223cab2bb3Spatrick u32 xchg,
2233cab2bb3Spatrick memory_order mo) {
2243cab2bb3Spatrick u32 cmpv = *cmp;
2253cab2bb3Spatrick u32 prev = (u32)_InterlockedCompareExchange(
2263cab2bb3Spatrick (volatile long*)&a->val_dont_use, (long)xchg, (long)cmpv);
2273cab2bb3Spatrick if (prev == cmpv)
2283cab2bb3Spatrick return true;
2293cab2bb3Spatrick *cmp = prev;
2303cab2bb3Spatrick return false;
2313cab2bb3Spatrick }
2323cab2bb3Spatrick
atomic_compare_exchange_strong(volatile atomic_uint64_t * a,u64 * cmp,u64 xchg,memory_order mo)233*d89ec533Spatrick inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a,
2343cab2bb3Spatrick u64 *cmp,
2353cab2bb3Spatrick u64 xchg,
2363cab2bb3Spatrick memory_order mo) {
2373cab2bb3Spatrick u64 cmpv = *cmp;
2383cab2bb3Spatrick u64 prev = (u64)_InterlockedCompareExchange64(
2393cab2bb3Spatrick (volatile long long*)&a->val_dont_use, (long long)xchg, (long long)cmpv);
2403cab2bb3Spatrick if (prev == cmpv)
2413cab2bb3Spatrick return true;
2423cab2bb3Spatrick *cmp = prev;
2433cab2bb3Spatrick return false;
2443cab2bb3Spatrick }
2453cab2bb3Spatrick
2463cab2bb3Spatrick template<typename T>
atomic_compare_exchange_weak(volatile T * a,typename T::Type * cmp,typename T::Type xchg,memory_order mo)247*d89ec533Spatrick inline bool atomic_compare_exchange_weak(volatile T *a,
2483cab2bb3Spatrick typename T::Type *cmp,
2493cab2bb3Spatrick typename T::Type xchg,
2503cab2bb3Spatrick memory_order mo) {
2513cab2bb3Spatrick return atomic_compare_exchange_strong(a, cmp, xchg, mo);
2523cab2bb3Spatrick }
2533cab2bb3Spatrick
2543cab2bb3Spatrick } // namespace __sanitizer
2553cab2bb3Spatrick
2563cab2bb3Spatrick #endif // SANITIZER_ATOMIC_CLANG_H
257